diff options
Diffstat (limited to 'drivers/net/ethernet/renesas/ravb_main.c')
-rw-r--r-- | drivers/net/ethernet/renesas/ravb_main.c | 148 |
1 files changed, 84 insertions, 64 deletions
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index c7ec23688d56..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: @@ -555,8 +554,16 @@ static void ravb_emac_init_gbeth(struct net_device *ndev) static void ravb_emac_init_rcar(struct net_device *ndev) { - /* Receive frame limit set register */ - ravb_write(ndev, ndev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN, RFLR); + struct ravb_private *priv = netdev_priv(ndev); + + /* Set receive frame length + * + * The length set here describes the frame from the destination address + * up to and including the CRC data. However only the frame data, + * excluding the CRC, are transferred to memory. To allow for the + * largest frames add the CRC length to the maximum Rx descriptor size. + */ + ravb_write(ndev, priv->info->rx_max_frame_size + ETH_FCS_LEN, RFLR); /* EMAC Mode: PAUSE prohibition; Duplex; RX Checksum; TX; RX */ ravb_write(ndev, ECMR_ZPF | ECMR_DM | @@ -742,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; - - /* 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. + size_t csum_len; + u16 *hw_csum; + + /* 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; } @@ -1742,20 +1745,19 @@ static int ravb_get_ts_info(struct net_device *ndev, struct ravb_private *priv = netdev_priv(ndev); const struct ravb_hw_info *hw_info = priv->info; - info->so_timestamping = - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_TX_HARDWARE | - SOF_TIMESTAMPING_RX_HARDWARE | - SOF_TIMESTAMPING_RAW_HARDWARE; - info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); - info->rx_filters = - (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_ALL); - if (hw_info->gptp || hw_info->ccc_gac) + if (hw_info->gptp || hw_info->ccc_gac) { + info->so_timestamping = + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + (1 << HWTSTAMP_FILTER_ALL); info->phc_index = ptp_clock_index(priv->ptp.clock); - else - info->phc_index = 0; + } return 0; } @@ -2060,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 */ @@ -2523,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; @@ -2534,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; @@ -2674,6 +2688,7 @@ static const struct ravb_hw_info ravb_gen2_hw_info = { .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, + .tx_max_frame_size = SZ_2K, .rx_max_frame_size = SZ_2K, .rx_buffer_size = SZ_2K + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), @@ -2696,6 +2711,7 @@ static const struct ravb_hw_info ravb_gen3_hw_info = { .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, + .tx_max_frame_size = SZ_2K, .rx_max_frame_size = SZ_2K, .rx_buffer_size = SZ_2K + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), @@ -2721,6 +2737,7 @@ static const struct ravb_hw_info ravb_gen4_hw_info = { .net_features = NETIF_F_RXCSUM, .stats_len = ARRAY_SIZE(ravb_gstrings_stats), .tccr_mask = TCCR_TSRQ0 | TCCR_TSRQ1 | TCCR_TSRQ2 | TCCR_TSRQ3, + .tx_max_frame_size = SZ_2K, .rx_max_frame_size = SZ_2K, .rx_buffer_size = SZ_2K + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), @@ -2768,8 +2785,10 @@ 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, .rx_max_frame_size = SZ_8K, .rx_buffer_size = SZ_2K, .rx_desc_size = sizeof(struct ravb_rx_desc), @@ -2909,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) @@ -2981,7 +3001,7 @@ static int ravb_probe(struct platform_device *pdev) priv->avb_link_active_low = of_property_read_bool(np, "renesas,ether-link-active-low"); - ndev->max_mtu = info->rx_max_frame_size - + ndev->max_mtu = info->tx_max_frame_size - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; @@ -3279,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), |