summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/renesas
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/renesas')
-rw-r--r--drivers/net/ethernet/renesas/ravb.h6
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c103
-rw-r--r--drivers/net/ethernet/renesas/rswitch.c2
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c2
4 files changed, 64 insertions, 49 deletions
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index a7de5cf6b317..7b48060c250b 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -998,6 +998,8 @@ enum CSR1_BIT {
CSR1_TDHD = 0x08000000,
};
+#define CSR1_CSUM_ENABLE (CSR1_TTCP4 | CSR1_TUDP4 | CSR1_TTCP6 | CSR1_TUDP6)
+
enum CSR2_BIT {
CSR2_RIP4 = 0x00000001,
CSR2_RTCP4 = 0x00000010,
@@ -1012,6 +1014,9 @@ enum CSR2_BIT {
CSR2_RDHD = 0x08000000,
};
+#define CSR2_CSUM_ENABLE (CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4 | \
+ CSR2_RTCP6 | CSR2_RUDP6 | CSR2_RICMP6)
+
#define DBAT_ENTRY_NUM 22
#define RX_QUEUE_OFFSET 4
#define NUM_RX_QUEUE 2
@@ -1050,6 +1055,7 @@ struct ravb_hw_info {
size_t gstrings_size;
netdev_features_t net_hw_features;
netdev_features_t net_features;
+ netdev_features_t vlan_features;
int stats_len;
u32 tccr_mask;
u32 tx_max_frame_size;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 907af4651c55..ac0f093f647a 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -504,11 +504,10 @@ static void ravb_csum_init_gbeth(struct net_device *ndev)
ndev->features &= ~NETIF_F_RXCSUM;
} else {
if (tx_enable)
- ravb_write(ndev, CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4, CSR1);
+ ravb_write(ndev, CSR1_CSUM_ENABLE, CSR1);
if (rx_enable)
- ravb_write(ndev, CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4,
- CSR2);
+ ravb_write(ndev, CSR2_CSUM_ENABLE, CSR2);
}
done:
@@ -750,38 +749,34 @@ static void ravb_get_tx_tstamp(struct net_device *ndev)
static void ravb_rx_csum_gbeth(struct sk_buff *skb)
{
struct skb_shared_info *shinfo = skb_shinfo(skb);
- __wsum csum_ip_hdr, csum_proto;
- skb_frag_t *last_frag;
- u8 *hw_csum;
+ size_t csum_len;
+ u16 *hw_csum;
- /* The hardware checksum status is contained in sizeof(__sum16) * 2 = 4
- * bytes appended to packet data. First 2 bytes is ip header checksum
- * and last 2 bytes is protocol checksum.
+ /* The hardware checksum status is contained in 4 bytes appended to
+ * packet data.
+ *
+ * For ipv4, the first 2 bytes are the ip header checksum status. We can
+ * ignore this as it will always be re-checked in inet_gro_receive().
+ *
+ * The last 2 bytes are the protocol checksum status which will be zero
+ * if the checksum has been validated.
*/
- if (unlikely(skb->len < sizeof(__sum16) * 2))
+ csum_len = sizeof(*hw_csum) * 2;
+ if (unlikely(skb->len < csum_len))
return;
if (skb_is_nonlinear(skb)) {
- last_frag = &shinfo->frags[shinfo->nr_frags - 1];
- hw_csum = skb_frag_address(last_frag) +
- skb_frag_size(last_frag);
+ skb_frag_t *last_frag = &shinfo->frags[shinfo->nr_frags - 1];
+
+ hw_csum = (u16 *)(skb_frag_address(last_frag) +
+ skb_frag_size(last_frag));
+ skb_frag_size_sub(last_frag, csum_len);
} else {
- hw_csum = skb_tail_pointer(skb);
+ hw_csum = (u16 *)skb_tail_pointer(skb);
+ skb_trim(skb, skb->len - csum_len);
}
- hw_csum -= sizeof(__sum16);
- csum_proto = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum));
-
- hw_csum -= sizeof(__sum16);
- csum_ip_hdr = csum_unfold((__force __sum16)get_unaligned_le16(hw_csum));
-
- if (skb_is_nonlinear(skb))
- skb_frag_size_sub(last_frag, 2 * sizeof(__sum16));
- else
- skb_trim(skb, skb->len - 2 * sizeof(__sum16));
-
- /* TODO: IPV6 Rx checksum */
- if (skb->protocol == htons(ETH_P_IP) && !csum_ip_hdr && !csum_proto)
+ if (!get_unaligned(--hw_csum))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -2067,32 +2062,44 @@ out_unlock:
static bool ravb_can_tx_csum_gbeth(struct sk_buff *skb)
{
- struct iphdr *ip = ip_hdr(skb);
+ u16 net_protocol = ntohs(skb->protocol);
+ u8 inner_protocol;
- /* TODO: Need to add support for VLAN tag 802.1Q */
- if (skb_vlan_tag_present(skb))
- return false;
+ /* GbEth IP can calculate the checksum if:
+ * - there are zero or one VLAN headers with TPID=0x8100
+ * - the network protocol is IPv4 or IPv6
+ * - the transport protocol is TCP, UDP or ICMP
+ * - the packet is not fragmented
+ */
- /* TODO: Need to add hardware checksum for IPv6 */
- if (skb->protocol != htons(ETH_P_IP))
- return false;
+ if (net_protocol == ETH_P_8021Q) {
+ struct vlan_hdr vhdr, *vh;
- switch (ip->protocol) {
- case IPPROTO_TCP:
- break;
- case IPPROTO_UDP:
- /* If the checksum value in the UDP header field is 0, TOE does
- * not calculate checksum for UDP part of this frame as it is
- * optional function as per standards.
- */
- if (udp_hdr(skb)->check == 0)
+ vh = skb_header_pointer(skb, ETH_HLEN, sizeof(vhdr), &vhdr);
+ if (!vh)
return false;
+
+ net_protocol = ntohs(vh->h_vlan_encapsulated_proto);
+ }
+
+ switch (net_protocol) {
+ case ETH_P_IP:
+ inner_protocol = ip_hdr(skb)->protocol;
+ break;
+ case ETH_P_IPV6:
+ inner_protocol = ipv6_hdr(skb)->nexthdr;
break;
default:
return false;
}
- return true;
+ switch (inner_protocol) {
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ return true;
+ default:
+ return false;
+ }
}
/* Packet transmit function for Ethernet AVB */
@@ -2530,7 +2537,7 @@ static int ravb_set_features_gbeth(struct net_device *ndev,
spin_lock_irqsave(&priv->lock, flags);
if (changed & NETIF_F_RXCSUM) {
if (features & NETIF_F_RXCSUM)
- val = CSR2_RIP4 | CSR2_RTCP4 | CSR2_RUDP4 | CSR2_RICMP4;
+ val = CSR2_CSUM_ENABLE;
else
val = 0;
@@ -2541,7 +2548,7 @@ static int ravb_set_features_gbeth(struct net_device *ndev,
if (changed & NETIF_F_HW_CSUM) {
if (features & NETIF_F_HW_CSUM)
- val = CSR1_TIP4 | CSR1_TTCP4 | CSR1_TUDP4;
+ val = CSR1_CSUM_ENABLE;
else
val = 0;
@@ -2778,6 +2785,7 @@ static const struct ravb_hw_info gbeth_hw_info = {
.gstrings_size = sizeof(ravb_gstrings_stats_gbeth),
.net_hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM,
.net_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM,
+ .vlan_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM,
.stats_len = ARRAY_SIZE(ravb_gstrings_stats_gbeth),
.tccr_mask = TCCR_TSRQ0,
.tx_max_frame_size = 1522,
@@ -2920,6 +2928,7 @@ static int ravb_probe(struct platform_device *pdev)
ndev->features = info->net_features;
ndev->hw_features = info->net_hw_features;
+ ndev->vlan_features = info->vlan_features;
error = reset_control_deassert(rstc);
if (error)
@@ -3290,7 +3299,7 @@ static const struct dev_pm_ops ravb_dev_pm_ops = {
static struct platform_driver ravb_driver = {
.probe = ravb_probe,
- .remove_new = ravb_remove,
+ .remove = ravb_remove,
.driver = {
.name = "ravb",
.pm = pm_ptr(&ravb_dev_pm_ops),
diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c
index b80aa27a7214..8d18dae4d8fb 100644
--- a/drivers/net/ethernet/renesas/rswitch.c
+++ b/drivers/net/ethernet/renesas/rswitch.c
@@ -2188,7 +2188,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(renesas_eth_sw_pm_ops, renesas_eth_sw_suspend,
static struct platform_driver renesas_eth_sw_driver_platform = {
.probe = renesas_eth_sw_probe,
- .remove_new = renesas_eth_sw_remove,
+ .remove = renesas_eth_sw_remove,
.driver = {
.name = "renesas_eth_sw",
.pm = pm_sleep_ptr(&renesas_eth_sw_pm_ops),
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 7a25903e35c3..8887b8921009 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -3560,7 +3560,7 @@ MODULE_DEVICE_TABLE(platform, sh_eth_id_table);
static struct platform_driver sh_eth_driver = {
.probe = sh_eth_drv_probe,
- .remove_new = sh_eth_drv_remove,
+ .remove = sh_eth_drv_remove,
.id_table = sh_eth_id_table,
.driver = {
.name = CARDNAME,