Commit d3ab9df5 authored by David S. Miller's avatar David S. Miller

Merge branch 'sh_eth-implement-simple-RX-checksum-offload'

Sergei Shtylyov says:

====================
sh_eth: implement simple RX checksum offload

Here's a set of 7 patches against DaveM's 'net-next.git' repo. I'm implemeting
the simple RX checksum offload (like was done for the 'ravb' driver by Simon
Horman); it has been only tested on the R8A7740 and R8A77980 SoCs, the other
SoCs should just work (according to their manuals)...
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cc733578 997feb11
...@@ -555,7 +555,7 @@ static int sh_eth_soft_reset_gether(struct net_device *ndev) ...@@ -555,7 +555,7 @@ static int sh_eth_soft_reset_gether(struct net_device *ndev)
sh_eth_write(ndev, 0, RDFFR); sh_eth_write(ndev, 0, RDFFR);
/* Reset HW CRC register */ /* Reset HW CRC register */
if (mdp->cd->hw_checksum) if (mdp->cd->csmr)
sh_eth_write(ndev, 0, CSMR); sh_eth_write(ndev, 0, CSMR);
/* Select MII mode */ /* Select MII mode */
...@@ -619,7 +619,8 @@ static struct sh_eth_cpu_data r7s72100_data = { ...@@ -619,7 +619,8 @@ static struct sh_eth_cpu_data r7s72100_data = {
.no_trimd = 1, .no_trimd = 1,
.no_ade = 1, .no_ade = 1,
.xdfar_rw = 1, .xdfar_rw = 1,
.hw_checksum = 1, .csmr = 1,
.rx_csum = 1,
.tsu = 1, .tsu = 1,
.no_tx_cntrs = 1, .no_tx_cntrs = 1,
}; };
...@@ -668,7 +669,8 @@ static struct sh_eth_cpu_data r8a7740_data = { ...@@ -668,7 +669,8 @@ static struct sh_eth_cpu_data r8a7740_data = {
.no_trimd = 1, .no_trimd = 1,
.no_ade = 1, .no_ade = 1,
.xdfar_rw = 1, .xdfar_rw = 1,
.hw_checksum = 1, .csmr = 1,
.rx_csum = 1,
.tsu = 1, .tsu = 1,
.select_mii = 1, .select_mii = 1,
.magic = 1, .magic = 1,
...@@ -793,7 +795,8 @@ static struct sh_eth_cpu_data r8a77980_data = { ...@@ -793,7 +795,8 @@ static struct sh_eth_cpu_data r8a77980_data = {
.no_trimd = 1, .no_trimd = 1,
.no_ade = 1, .no_ade = 1,
.xdfar_rw = 1, .xdfar_rw = 1,
.hw_checksum = 1, .csmr = 1,
.rx_csum = 1,
.select_mii = 1, .select_mii = 1,
.magic = 1, .magic = 1,
.cexcr = 1, .cexcr = 1,
...@@ -1045,7 +1048,8 @@ static struct sh_eth_cpu_data sh7734_data = { ...@@ -1045,7 +1048,8 @@ static struct sh_eth_cpu_data sh7734_data = {
.no_ade = 1, .no_ade = 1,
.xdfar_rw = 1, .xdfar_rw = 1,
.tsu = 1, .tsu = 1,
.hw_checksum = 1, .csmr = 1,
.rx_csum = 1,
.select_mii = 1, .select_mii = 1,
.magic = 1, .magic = 1,
.cexcr = 1, .cexcr = 1,
...@@ -1088,6 +1092,7 @@ static struct sh_eth_cpu_data sh7763_data = { ...@@ -1088,6 +1092,7 @@ static struct sh_eth_cpu_data sh7763_data = {
.irq_flags = IRQF_SHARED, .irq_flags = IRQF_SHARED,
.magic = 1, .magic = 1,
.cexcr = 1, .cexcr = 1,
.rx_csum = 1,
.dual_port = 1, .dual_port = 1,
}; };
...@@ -1532,8 +1537,9 @@ static int sh_eth_dev_init(struct net_device *ndev) ...@@ -1532,8 +1537,9 @@ static int sh_eth_dev_init(struct net_device *ndev)
mdp->irq_enabled = true; mdp->irq_enabled = true;
sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR); sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
/* PAUSE Prohibition */ /* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */
sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | sh_eth_write(ndev, ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) |
(ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) |
ECMR_TE | ECMR_RE, ECMR); ECMR_TE | ECMR_RE, ECMR);
if (mdp->cd->set_rate) if (mdp->cd->set_rate)
...@@ -1592,6 +1598,19 @@ static void sh_eth_dev_exit(struct net_device *ndev) ...@@ -1592,6 +1598,19 @@ static void sh_eth_dev_exit(struct net_device *ndev)
update_mac_address(ndev); update_mac_address(ndev);
} }
static void sh_eth_rx_csum(struct sk_buff *skb)
{
u8 *hw_csum;
/* The hardware checksum is 2 bytes appended to packet data */
if (unlikely(skb->len < sizeof(__sum16)))
return;
hw_csum = skb_tail_pointer(skb) - sizeof(__sum16);
skb->csum = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum));
skb->ip_summed = CHECKSUM_COMPLETE;
skb_trim(skb, skb->len - sizeof(__sum16));
}
/* Packet receive function */ /* Packet receive function */
static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
{ {
...@@ -1633,7 +1652,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) ...@@ -1633,7 +1652,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
* the RFS bits are from bit 25 to bit 16. So, the * the RFS bits are from bit 25 to bit 16. So, the
* driver needs right shifting by 16. * driver needs right shifting by 16.
*/ */
if (mdp->cd->hw_checksum) if (mdp->cd->csmr)
desc_status >>= 16; desc_status >>= 16;
skb = mdp->rx_skbuff[entry]; skb = mdp->rx_skbuff[entry];
...@@ -1666,6 +1685,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) ...@@ -1666,6 +1685,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
skb_put(skb, pkt_len); skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
if (ndev->features & NETIF_F_RXCSUM)
sh_eth_rx_csum(skb);
netif_receive_skb(skb); netif_receive_skb(skb);
ndev->stats.rx_packets++; ndev->stats.rx_packets++;
ndev->stats.rx_bytes += pkt_len; ndev->stats.rx_bytes += pkt_len;
...@@ -2173,7 +2194,7 @@ static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf) ...@@ -2173,7 +2194,7 @@ static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf)
add_reg(MAFCR); add_reg(MAFCR);
if (cd->rtrate) if (cd->rtrate)
add_reg(RTRATE); add_reg(RTRATE);
if (cd->hw_checksum) if (cd->csmr)
add_reg(CSMR); add_reg(CSMR);
if (cd->select_mii) if (cd->select_mii)
add_reg(RMII_MII); add_reg(RMII_MII);
...@@ -2921,6 +2942,39 @@ static void sh_eth_set_rx_mode(struct net_device *ndev) ...@@ -2921,6 +2942,39 @@ static void sh_eth_set_rx_mode(struct net_device *ndev)
spin_unlock_irqrestore(&mdp->lock, flags); spin_unlock_irqrestore(&mdp->lock, flags);
} }
static void sh_eth_set_rx_csum(struct net_device *ndev, bool enable)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
unsigned long flags;
spin_lock_irqsave(&mdp->lock, flags);
/* Disable TX and RX */
sh_eth_rcv_snd_disable(ndev);
/* Modify RX Checksum setting */
sh_eth_modify(ndev, ECMR, ECMR_RCSC, enable ? ECMR_RCSC : 0);
/* Enable TX and RX */
sh_eth_rcv_snd_enable(ndev);
spin_unlock_irqrestore(&mdp->lock, flags);
}
static int sh_eth_set_features(struct net_device *ndev,
netdev_features_t features)
{
netdev_features_t changed = ndev->features ^ features;
struct sh_eth_private *mdp = netdev_priv(ndev);
if (changed & NETIF_F_RXCSUM && mdp->cd->rx_csum)
sh_eth_set_rx_csum(ndev, features & NETIF_F_RXCSUM);
ndev->features = features;
return 0;
}
static int sh_eth_get_vtag_index(struct sh_eth_private *mdp) static int sh_eth_get_vtag_index(struct sh_eth_private *mdp)
{ {
if (!mdp->port) if (!mdp->port)
...@@ -3102,6 +3156,7 @@ static const struct net_device_ops sh_eth_netdev_ops = { ...@@ -3102,6 +3156,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {
.ndo_change_mtu = sh_eth_change_mtu, .ndo_change_mtu = sh_eth_change_mtu,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = eth_mac_addr,
.ndo_set_features = sh_eth_set_features,
}; };
static const struct net_device_ops sh_eth_netdev_ops_tsu = { static const struct net_device_ops sh_eth_netdev_ops_tsu = {
...@@ -3117,6 +3172,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = { ...@@ -3117,6 +3172,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {
.ndo_change_mtu = sh_eth_change_mtu, .ndo_change_mtu = sh_eth_change_mtu,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr, .ndo_set_mac_address = eth_mac_addr,
.ndo_set_features = sh_eth_set_features,
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -3245,6 +3301,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ...@@ -3245,6 +3301,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->max_mtu = 2000 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN);
ndev->min_mtu = ETH_MIN_MTU; ndev->min_mtu = ETH_MIN_MTU;
if (mdp->cd->rx_csum) {
ndev->features = NETIF_F_RXCSUM;
ndev->hw_features = NETIF_F_RXCSUM;
}
/* set function */ /* set function */
if (mdp->cd->tsu) if (mdp->cd->tsu)
ndev->netdev_ops = &sh_eth_netdev_ops_tsu; ndev->netdev_ops = &sh_eth_netdev_ops_tsu;
...@@ -3294,7 +3355,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ...@@ -3294,7 +3355,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
goto out_release; goto out_release;
} }
mdp->port = port; mdp->port = port;
ndev->features = NETIF_F_HW_VLAN_CTAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
/* Need to init only the first port of the two sharing a TSU */ /* Need to init only the first port of the two sharing a TSU */
if (port == 0) { if (port == 0) {
......
...@@ -499,7 +499,8 @@ struct sh_eth_cpu_data { ...@@ -499,7 +499,8 @@ struct sh_eth_cpu_data {
unsigned no_ade:1; /* E-DMAC DOES NOT have ADE bit in EESR */ unsigned no_ade:1; /* E-DMAC DOES NOT have ADE bit in EESR */
unsigned no_xdfar:1; /* E-DMAC DOES NOT have RDFAR/TDFAR */ unsigned no_xdfar:1; /* E-DMAC DOES NOT have RDFAR/TDFAR */
unsigned xdfar_rw:1; /* E-DMAC has writeable RDFAR/TDFAR */ unsigned xdfar_rw:1; /* E-DMAC has writeable RDFAR/TDFAR */
unsigned hw_checksum:1; /* E-DMAC has CSMR */ unsigned csmr:1; /* E-DMAC has CSMR */
unsigned rx_csum:1; /* EtherC has ECMR.RCSC */
unsigned select_mii:1; /* EtherC has RMII_MII (MII select register) */ unsigned select_mii:1; /* EtherC has RMII_MII (MII select register) */
unsigned rmiimode:1; /* EtherC has RMIIMODE register */ unsigned rmiimode:1; /* EtherC has RMIIMODE register */
unsigned rtrate:1; /* EtherC has RTRATE register */ unsigned rtrate:1; /* EtherC has RTRATE register */
......
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