Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+70 −9
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ static int sh_eth_soft_reset_gether(struct net_device *ndev)
	sh_eth_write(ndev, 0, RDFFR);

	/* Reset HW CRC register */
	if (mdp->cd->hw_checksum)
	if (mdp->cd->csmr)
		sh_eth_write(ndev, 0, CSMR);

	/* Select MII mode */
@@ -619,7 +619,8 @@ static struct sh_eth_cpu_data r7s72100_data = {
	.no_trimd	= 1,
	.no_ade		= 1,
	.xdfar_rw	= 1,
	.hw_checksum	= 1,
	.csmr		= 1,
	.rx_csum	= 1,
	.tsu		= 1,
	.no_tx_cntrs	= 1,
};
@@ -668,7 +669,8 @@ static struct sh_eth_cpu_data r8a7740_data = {
	.no_trimd	= 1,
	.no_ade		= 1,
	.xdfar_rw	= 1,
	.hw_checksum	= 1,
	.csmr		= 1,
	.rx_csum	= 1,
	.tsu		= 1,
	.select_mii	= 1,
	.magic		= 1,
@@ -793,7 +795,8 @@ static struct sh_eth_cpu_data r8a77980_data = {
	.no_trimd	= 1,
	.no_ade		= 1,
	.xdfar_rw	= 1,
	.hw_checksum	= 1,
	.csmr		= 1,
	.rx_csum	= 1,
	.select_mii	= 1,
	.magic		= 1,
	.cexcr		= 1,
@@ -1045,7 +1048,8 @@ static struct sh_eth_cpu_data sh7734_data = {
	.no_ade		= 1,
	.xdfar_rw	= 1,
	.tsu		= 1,
	.hw_checksum	= 1,
	.csmr		= 1,
	.rx_csum	= 1,
	.select_mii	= 1,
	.magic		= 1,
	.cexcr		= 1,
@@ -1088,6 +1092,7 @@ static struct sh_eth_cpu_data sh7763_data = {
	.irq_flags	= IRQF_SHARED,
	.magic		= 1,
	.cexcr		= 1,
	.rx_csum	= 1,
	.dual_port	= 1,
};

@@ -1532,8 +1537,9 @@ static int sh_eth_dev_init(struct net_device *ndev)
	mdp->irq_enabled = true;
	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) |
		     (ndev->features & NETIF_F_RXCSUM ? ECMR_RCSC : 0) |
		     ECMR_TE | ECMR_RE, ECMR);

	if (mdp->cd->set_rate)
@@ -1592,6 +1598,19 @@ static void sh_eth_dev_exit(struct net_device *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 */
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
		 * driver needs right shifting by 16.
		 */
		if (mdp->cd->hw_checksum)
		if (mdp->cd->csmr)
			desc_status >>= 16;

		skb = mdp->rx_skbuff[entry];
@@ -1666,6 +1685,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
					 DMA_FROM_DEVICE);
			skb_put(skb, pkt_len);
			skb->protocol = eth_type_trans(skb, ndev);
			if (ndev->features & NETIF_F_RXCSUM)
				sh_eth_rx_csum(skb);
			netif_receive_skb(skb);
			ndev->stats.rx_packets++;
			ndev->stats.rx_bytes += pkt_len;
@@ -2173,7 +2194,7 @@ static size_t __sh_eth_get_regs(struct net_device *ndev, u32 *buf)
	add_reg(MAFCR);
	if (cd->rtrate)
		add_reg(RTRATE);
	if (cd->hw_checksum)
	if (cd->csmr)
		add_reg(CSMR);
	if (cd->select_mii)
		add_reg(RMII_MII);
@@ -2921,6 +2942,39 @@ static void sh_eth_set_rx_mode(struct net_device *ndev)
	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)
{
	if (!mdp->port)
@@ -3102,6 +3156,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {
	.ndo_change_mtu		= sh_eth_change_mtu,
	.ndo_validate_addr	= eth_validate_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 = {
@@ -3117,6 +3172,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {
	.ndo_change_mtu		= sh_eth_change_mtu,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_set_features	= sh_eth_set_features,
};

#ifdef CONFIG_OF
@@ -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->min_mtu = ETH_MIN_MTU;

	if (mdp->cd->rx_csum) {
		ndev->features = NETIF_F_RXCSUM;
		ndev->hw_features = NETIF_F_RXCSUM;
	}

	/* set function */
	if (mdp->cd->tsu)
		ndev->netdev_ops = &sh_eth_netdev_ops_tsu;
@@ -3294,7 +3355,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
			goto out_release;
		}
		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 */
		if (port == 0) {
+2 −1
Original line number Diff line number Diff line
@@ -499,7 +499,8 @@ struct sh_eth_cpu_data {
	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 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 rmiimode:1;	/* EtherC has RMIIMODE register */
	unsigned rtrate:1;	/* EtherC has RTRATE register */