diff options
Diffstat (limited to 'drivers/net/ethernet/mediatek/mtk_eth_soc.c')
-rw-r--r-- | drivers/net/ethernet/mediatek/mtk_eth_soc.c | 95 |
1 files changed, 68 insertions, 27 deletions
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index d01b3a1b40f4..f9139150a8a2 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -215,7 +215,7 @@ static void mtk_mac_config(struct phylink_config *config, unsigned int mode, phylink_config); struct mtk_eth *eth = mac->hw; u32 mcr_cur, mcr_new, sid, i; - int val, ge_mode, err; + int val, ge_mode, err = 0; /* MT76x8 has no hardware settings between for the MAC */ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && @@ -675,32 +675,53 @@ static int mtk_set_mac_address(struct net_device *dev, void *p) void mtk_stats_update_mac(struct mtk_mac *mac) { struct mtk_hw_stats *hw_stats = mac->hw_stats; - unsigned int base = MTK_GDM1_TX_GBCNT; - u64 stats; - - base += hw_stats->reg_offset; + struct mtk_eth *eth = mac->hw; u64_stats_update_begin(&hw_stats->syncp); - hw_stats->rx_bytes += mtk_r32(mac->hw, base); - stats = mtk_r32(mac->hw, base + 0x04); - if (stats) - hw_stats->rx_bytes += (stats << 32); - hw_stats->rx_packets += mtk_r32(mac->hw, base + 0x08); - hw_stats->rx_overflow += mtk_r32(mac->hw, base + 0x10); - hw_stats->rx_fcs_errors += mtk_r32(mac->hw, base + 0x14); - hw_stats->rx_short_errors += mtk_r32(mac->hw, base + 0x18); - hw_stats->rx_long_errors += mtk_r32(mac->hw, base + 0x1c); - hw_stats->rx_checksum_errors += mtk_r32(mac->hw, base + 0x20); - hw_stats->rx_flow_control_packets += - mtk_r32(mac->hw, base + 0x24); - hw_stats->tx_skip += mtk_r32(mac->hw, base + 0x28); - hw_stats->tx_collisions += mtk_r32(mac->hw, base + 0x2c); - hw_stats->tx_bytes += mtk_r32(mac->hw, base + 0x30); - stats = mtk_r32(mac->hw, base + 0x34); - if (stats) - hw_stats->tx_bytes += (stats << 32); - hw_stats->tx_packets += mtk_r32(mac->hw, base + 0x38); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + hw_stats->tx_packets += mtk_r32(mac->hw, MT7628_SDM_TPCNT); + hw_stats->tx_bytes += mtk_r32(mac->hw, MT7628_SDM_TBCNT); + hw_stats->rx_packets += mtk_r32(mac->hw, MT7628_SDM_RPCNT); + hw_stats->rx_bytes += mtk_r32(mac->hw, MT7628_SDM_RBCNT); + hw_stats->rx_checksum_errors += + mtk_r32(mac->hw, MT7628_SDM_CS_ERR); + } else { + unsigned int offs = hw_stats->reg_offset; + u64 stats; + + hw_stats->rx_bytes += mtk_r32(mac->hw, + MTK_GDM1_RX_GBCNT_L + offs); + stats = mtk_r32(mac->hw, MTK_GDM1_RX_GBCNT_H + offs); + if (stats) + hw_stats->rx_bytes += (stats << 32); + hw_stats->rx_packets += + mtk_r32(mac->hw, MTK_GDM1_RX_GPCNT + offs); + hw_stats->rx_overflow += + mtk_r32(mac->hw, MTK_GDM1_RX_OERCNT + offs); + hw_stats->rx_fcs_errors += + mtk_r32(mac->hw, MTK_GDM1_RX_FERCNT + offs); + hw_stats->rx_short_errors += + mtk_r32(mac->hw, MTK_GDM1_RX_SERCNT + offs); + hw_stats->rx_long_errors += + mtk_r32(mac->hw, MTK_GDM1_RX_LENCNT + offs); + hw_stats->rx_checksum_errors += + mtk_r32(mac->hw, MTK_GDM1_RX_CERCNT + offs); + hw_stats->rx_flow_control_packets += + mtk_r32(mac->hw, MTK_GDM1_RX_FCCNT + offs); + hw_stats->tx_skip += + mtk_r32(mac->hw, MTK_GDM1_TX_SKIPCNT + offs); + hw_stats->tx_collisions += + mtk_r32(mac->hw, MTK_GDM1_TX_COLCNT + offs); + hw_stats->tx_bytes += + mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_L + offs); + stats = mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_H + offs); + if (stats) + hw_stats->tx_bytes += (stats << 32); + hw_stats->tx_packets += + mtk_r32(mac->hw, MTK_GDM1_TX_GPCNT + offs); + } + u64_stats_update_end(&hw_stats->syncp); } @@ -781,6 +802,17 @@ static inline void mtk_rx_get_desc(struct mtk_rx_dma *rxd, rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); } +static void *mtk_max_lro_buf_alloc(gfp_t gfp_mask) +{ + unsigned int size = mtk_max_frag_size(MTK_MAX_LRO_RX_LENGTH); + unsigned long data; + + data = __get_free_pages(gfp_mask | __GFP_COMP | __GFP_NOWARN, + get_order(size)); + + return (void *)data; +} + /* the qdma core needs scratch memory to be setup */ static int mtk_init_fq_dma(struct mtk_eth *eth) { @@ -1278,7 +1310,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, goto release_desc; /* alloc new buffer */ - new_data = napi_alloc_frag(ring->frag_size); + if (ring->frag_size <= PAGE_SIZE) + new_data = napi_alloc_frag(ring->frag_size); + else + new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); if (unlikely(!new_data)) { netdev->stats.rx_dropped++; goto release_desc; @@ -1315,7 +1350,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, skb->protocol = eth_type_trans(skb, netdev); if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && - RX_DMA_VID(trxd.rxd3)) + (trxd.rxd2 & RX_DMA_VTAG)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), RX_DMA_VID(trxd.rxd3)); skb_record_rx_queue(skb, 0); @@ -1675,7 +1710,10 @@ static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) return -ENOMEM; for (i = 0; i < rx_dma_size; i++) { - ring->data[i] = netdev_alloc_frag(ring->frag_size); + if (ring->frag_size <= PAGE_SIZE) + ring->data[i] = netdev_alloc_frag(ring->frag_size); + else + ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); if (!ring->data[i]) return -ENOMEM; } @@ -1941,6 +1979,9 @@ static int mtk_hwlro_get_fdir_entry(struct net_device *dev, struct ethtool_rx_flow_spec *fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; + if (fsp->location >= ARRAY_SIZE(mac->hwlro_ip)) + return -EINVAL; + /* only tcp dst ipv4 is meaningful, others are meaningless */ fsp->flow_type = TCP_V4_FLOW; fsp->h_u.tcp_ip4_spec.ip4dst = ntohl(mac->hwlro_ip[fsp->location]); |