--- zzzz-none-000/linux-3.10.107/drivers/net/ethernet/tile/tilepro.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/ethernet/tile/tilepro.c 2021-02-04 17:41:59.000000000 +0000 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -88,13 +89,6 @@ /* ISSUE: This has not been thoroughly tested (except at 1500). */ #define TILE_NET_MTU 1500 -/* HACK: Define to support GSO. */ -/* ISSUE: This may actually hurt performance of the TCP blaster. */ -/* #define TILE_NET_GSO */ - -/* Define this to collapse "duplicate" acks. */ -/* #define IGNORE_DUP_ACKS */ - /* HACK: Define this to verify incoming packets. */ /* #define TILE_NET_VERIFY_INGRESS */ @@ -156,10 +150,13 @@ * Statistics counters for a specific cpu and device. */ struct tile_net_stats_t { - u32 rx_packets; - u32 rx_bytes; - u32 tx_packets; - u32 tx_bytes; + struct u64_stats_sync syncp; + u64 rx_packets; /* total packets received */ + u64 tx_packets; /* total packets transmitted */ + u64 rx_bytes; /* total bytes received */ + u64 tx_bytes; /* total bytes transmitted */ + u64 rx_errors; /* packets truncated or marked bad by hw */ + u64 rx_dropped; /* packets not for us or intf not up */ }; @@ -218,8 +215,6 @@ int network_cpus_count; /* Credits per network cpu. */ int network_cpus_credits; - /* Network stats. */ - struct net_device_stats stats; /* For NetIO bringup retries. */ struct delayed_work retry_work; /* Quick access to per cpu data. */ @@ -627,79 +622,6 @@ } -#ifdef IGNORE_DUP_ACKS - -/* - * Help detect "duplicate" ACKs. These are sequential packets (for a - * given flow) which are exactly 66 bytes long, sharing everything but - * ID=2@0x12, Hsum=2@0x18, Ack=4@0x2a, WinSize=2@0x30, Csum=2@0x32, - * Tstamps=10@0x38. The ID's are +1, the Hsum's are -1, the Ack's are - * +N, and the Tstamps are usually identical. - * - * NOTE: Apparently truly duplicate acks (with identical "ack" values), - * should not be collapsed, as they are used for some kind of flow control. - */ -static bool is_dup_ack(char *s1, char *s2, unsigned int len) -{ - int i; - - unsigned long long ignorable = 0; - - /* Identification. */ - ignorable |= (1ULL << 0x12); - ignorable |= (1ULL << 0x13); - - /* Header checksum. */ - ignorable |= (1ULL << 0x18); - ignorable |= (1ULL << 0x19); - - /* ACK. */ - ignorable |= (1ULL << 0x2a); - ignorable |= (1ULL << 0x2b); - ignorable |= (1ULL << 0x2c); - ignorable |= (1ULL << 0x2d); - - /* WinSize. */ - ignorable |= (1ULL << 0x30); - ignorable |= (1ULL << 0x31); - - /* Checksum. */ - ignorable |= (1ULL << 0x32); - ignorable |= (1ULL << 0x33); - - for (i = 0; i < len; i++, ignorable >>= 1) { - - if ((ignorable & 1) || (s1[i] == s2[i])) - continue; - -#ifdef TILE_NET_DEBUG - /* HACK: Mention non-timestamp diffs. */ - if (i < 0x38 && i != 0x2f && - net_ratelimit()) - pr_info("Diff at 0x%x\n", i); -#endif - - return false; - } - -#ifdef TILE_NET_NO_SUPPRESS_DUP_ACKS - /* HACK: Do not suppress truly duplicate ACKs. */ - /* ISSUE: Is this actually necessary or helpful? */ - if (s1[0x2a] == s2[0x2a] && - s1[0x2b] == s2[0x2b] && - s1[0x2c] == s2[0x2c] && - s1[0x2d] == s2[0x2d]) { - return false; - } -#endif - - return true; -} - -#endif - - - static void tile_net_discard_aux(struct tile_net_cpu *info, int index) { struct tile_netio_queue *queue = &info->queue; @@ -774,6 +696,7 @@ netio_pkt_t *pkt = (netio_pkt_t *)((unsigned long) &qsp[1] + index); netio_pkt_metadata_t *metadata = NETIO_PKT_METADATA(pkt); + netio_pkt_status_t pkt_status = NETIO_PKT_STATUS_M(metadata, pkt); /* Extract the packet size. FIXME: Shouldn't the second line */ /* get subtracted? Mostly moot, since it should be "zero". */ @@ -798,48 +721,30 @@ if (!hash_default) __inv_buffer(buf, len); - /* ISSUE: Is this needed? */ - dev->last_rx = jiffies; - #ifdef TILE_NET_DUMP_PACKETS dump_packet(buf, len, "rx"); #endif /* TILE_NET_DUMP_PACKETS */ #ifdef TILE_NET_VERIFY_INGRESS - if (!NETIO_PKT_L4_CSUM_CORRECT_M(metadata, pkt) && - NETIO_PKT_L4_CSUM_CALCULATED_M(metadata, pkt)) { - /* Bug 6624: Includes UDP packets with a "zero" checksum. */ - pr_warning("Bad L4 checksum on %d byte packet.\n", len); - } - if (!NETIO_PKT_L3_CSUM_CORRECT_M(metadata, pkt) && - NETIO_PKT_L3_CSUM_CALCULATED_M(metadata, pkt)) { + if (pkt_status == NETIO_PKT_STATUS_OVERSIZE && len >= 64) { dump_packet(buf, len, "rx"); - panic("Bad L3 checksum."); - } - switch (NETIO_PKT_STATUS_M(metadata, pkt)) { - case NETIO_PKT_STATUS_OVERSIZE: - if (len >= 64) { - dump_packet(buf, len, "rx"); - panic("Unexpected OVERSIZE."); - } - break; - case NETIO_PKT_STATUS_BAD: - pr_warning("Unexpected BAD %ld byte packet.\n", len); + panic("Unexpected OVERSIZE."); } #endif filter = 0; - /* ISSUE: Filter TCP packets with "bad" checksums? */ - - if (!(dev->flags & IFF_UP)) { + if (pkt_status == NETIO_PKT_STATUS_BAD) { + /* Handle CRC error and hardware truncation. */ + filter = 2; + } else if (!(dev->flags & IFF_UP)) { /* Filter packets received before we're up. */ filter = 1; - } else if (NETIO_PKT_STATUS_M(metadata, pkt) == NETIO_PKT_STATUS_BAD) { + } else if (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(metadata, pkt) && + pkt_status == NETIO_PKT_STATUS_UNDERSIZE) { /* Filter "truncated" packets. */ - filter = 1; + filter = 2; } else if (!(dev->flags & IFF_PROMISC)) { - /* FIXME: Implement HW multicast filter. */ if (!is_multicast_ether_addr(buf)) { /* Filter packets not for our address. */ const u8 *mine = dev->dev_addr; @@ -847,9 +752,14 @@ } } - if (filter) { + u64_stats_update_begin(&stats->syncp); - /* ISSUE: Update "drop" statistics? */ + if (filter != 0) { + + if (filter == 1) + stats->rx_dropped++; + else + stats->rx_errors++; tile_net_provide_linux_buffer(info, va, small); @@ -881,6 +791,8 @@ stats->rx_bytes += len; } + u64_stats_update_end(&stats->syncp); + /* ISSUE: It would be nice to defer this until the packet has */ /* actually been processed. */ tile_net_return_credit(info); @@ -916,6 +828,9 @@ unsigned int work = 0; + if (budget <= 0) + goto done; + while (priv->active) { int index = qup->__packet_receive_read; if (index == qsp->__packet_receive_queue.__packet_write) @@ -1038,7 +953,7 @@ */ if (hv_dev_pwrite(priv->hv_devhdl, 0, (HV_VirtAddr)&dummy, sizeof(dummy), NETIO_IPP_START_SHIM_OFF) < 0) { - pr_warning("Failed to start LIPP/LEPP.\n"); + pr_warn("Failed to start LIPP/LEPP\n"); return -EIO; } @@ -1078,13 +993,13 @@ PDEBUG("tile_net_register(queue_id %d)\n", queue_id); if (!strcmp(dev->name, "xgbe0")) - info = &__get_cpu_var(hv_xgbe0); + info = this_cpu_ptr(&hv_xgbe0); else if (!strcmp(dev->name, "xgbe1")) - info = &__get_cpu_var(hv_xgbe1); + info = this_cpu_ptr(&hv_xgbe1); else if (!strcmp(dev->name, "gbe0")) - info = &__get_cpu_var(hv_gbe0); + info = this_cpu_ptr(&hv_gbe0); else if (!strcmp(dev->name, "gbe1")) - info = &__get_cpu_var(hv_gbe1); + info = this_cpu_ptr(&hv_gbe1); else BUG(); @@ -1093,6 +1008,8 @@ info->egress_timer.data = (long)info; info->egress_timer.function = tile_net_handle_egress_timer; + u64_stats_init(&info->stats.syncp); + priv->cpu[my_cpu] = info; /* @@ -1904,11 +1821,13 @@ /* Handle completions. */ for (i = 0; i < nolds; i++) - kfree_skb(olds[i]); + dev_consume_skb_any(olds[i]); /* Update stats. */ + u64_stats_update_begin(&stats->syncp); stats->tx_packets += num_segs; stats->tx_bytes += (num_segs * sh_len) + d_len; + u64_stats_update_end(&stats->syncp); /* Make sure the egress timer is scheduled. */ tile_net_schedule_egress_timer(info); @@ -1936,7 +1855,7 @@ unsigned int csum_start = skb_checksum_start_offset(skb); - lepp_frag_t frags[LEPP_MAX_FRAGS]; + lepp_frag_t frags[1 + MAX_SKB_FRAGS]; unsigned int num_frags; @@ -1951,7 +1870,7 @@ unsigned int cmd_head, cmd_tail, cmd_next; unsigned int comp_tail; - lepp_cmd_t cmds[LEPP_MAX_FRAGS]; + lepp_cmd_t cmds[1 + MAX_SKB_FRAGS]; /* @@ -2086,11 +2005,13 @@ /* Handle completions. */ for (i = 0; i < nolds; i++) - kfree_skb(olds[i]); + dev_consume_skb_any(olds[i]); /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */ + u64_stats_update_begin(&stats->syncp); stats->tx_packets++; stats->tx_bytes += ((len >= ETH_ZLEN) ? len : ETH_ZLEN); + u64_stats_update_end(&stats->syncp); /* Make sure the egress timer is scheduled. */ tile_net_schedule_egress_timer(info); @@ -2127,30 +2048,51 @@ * * Returns the address of the device statistics structure. */ -static struct net_device_stats *tile_net_get_stats(struct net_device *dev) +static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) { struct tile_net_priv *priv = netdev_priv(dev); - u32 rx_packets = 0; - u32 tx_packets = 0; - u32 rx_bytes = 0; - u32 tx_bytes = 0; + u64 rx_packets = 0, tx_packets = 0; + u64 rx_bytes = 0, tx_bytes = 0; + u64 rx_errors = 0, rx_dropped = 0; int i; for_each_online_cpu(i) { - if (priv->cpu[i]) { - rx_packets += priv->cpu[i]->stats.rx_packets; - rx_bytes += priv->cpu[i]->stats.rx_bytes; - tx_packets += priv->cpu[i]->stats.tx_packets; - tx_bytes += priv->cpu[i]->stats.tx_bytes; - } - } + struct tile_net_stats_t *cpu_stats; + u64 trx_packets, ttx_packets, trx_bytes, ttx_bytes; + u64 trx_errors, trx_dropped; + unsigned int start; + + if (priv->cpu[i] == NULL) + continue; + cpu_stats = &priv->cpu[i]->stats; - priv->stats.rx_packets = rx_packets; - priv->stats.rx_bytes = rx_bytes; - priv->stats.tx_packets = tx_packets; - priv->stats.tx_bytes = tx_bytes; + do { + start = u64_stats_fetch_begin_irq(&cpu_stats->syncp); + trx_packets = cpu_stats->rx_packets; + ttx_packets = cpu_stats->tx_packets; + trx_bytes = cpu_stats->rx_bytes; + ttx_bytes = cpu_stats->tx_bytes; + trx_errors = cpu_stats->rx_errors; + trx_dropped = cpu_stats->rx_dropped; + } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start)); + + rx_packets += trx_packets; + tx_packets += ttx_packets; + rx_bytes += trx_bytes; + tx_bytes += ttx_bytes; + rx_errors += trx_errors; + rx_dropped += trx_dropped; + } + + stats->rx_packets = rx_packets; + stats->tx_packets = tx_packets; + stats->rx_bytes = rx_bytes; + stats->tx_bytes = tx_bytes; + stats->rx_errors = rx_errors; + stats->rx_dropped = rx_dropped; - return &priv->stats; + return stats; } @@ -2287,7 +2229,7 @@ .ndo_stop = tile_net_stop, .ndo_start_xmit = tile_net_tx, .ndo_do_ioctl = tile_net_ioctl, - .ndo_get_stats = tile_net_get_stats, + .ndo_get_stats64 = tile_net_get_stats64, .ndo_change_mtu = tile_net_change_mtu, .ndo_tx_timeout = tile_net_tx_timeout, .ndo_set_mac_address = tile_net_set_mac_address, @@ -2305,39 +2247,30 @@ */ static void tile_net_setup(struct net_device *dev) { - PDEBUG("tile_net_setup()\n"); + netdev_features_t features = 0; ether_setup(dev); - dev->netdev_ops = &tile_net_ops; - dev->watchdog_timeo = TILE_NET_TIMEOUT; + dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN; + dev->mtu = TILE_NET_MTU; - /* We want lockless xmit. */ - dev->features |= NETIF_F_LLTX; - - /* We support hardware tx checksums. */ - dev->features |= NETIF_F_HW_CSUM; - - /* We support scatter/gather. */ - dev->features |= NETIF_F_SG; - - /* We support TSO. */ - dev->features |= NETIF_F_TSO; + features |= NETIF_F_HW_CSUM; + features |= NETIF_F_SG; -#ifdef TILE_NET_GSO - /* We support GSO. */ - dev->features |= NETIF_F_GSO; -#endif + /* We support TSO iff the HV supports sufficient frags. */ + if (LEPP_MAX_FRAGS >= 1 + MAX_SKB_FRAGS) + features |= NETIF_F_TSO; + /* We can't support HIGHDMA without hash_default, since we need + * to be able to finv() with a VA if we don't have hash_default. + */ if (hash_default) - dev->features |= NETIF_F_HIGHDMA; + features |= NETIF_F_HIGHDMA; - /* ISSUE: We should support NETIF_F_UFO. */ - - dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN; - - dev->mtu = TILE_NET_MTU; + dev->hw_features |= features; + dev->vlan_features |= features; + dev->features |= features; } @@ -2356,7 +2289,8 @@ * tile_net_setup(), and saves "name". Normally, "name" is a * template, instantiated by register_netdev(), but not for us. */ - dev = alloc_netdev(sizeof(*priv), name, tile_net_setup); + dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, + tile_net_setup); if (!dev) { pr_err("alloc_netdev(%s) failed\n", name); return NULL; @@ -2462,8 +2396,7 @@ { int rc = cpulist_parse_crop(str, &network_cpus_map); if (rc != 0) { - pr_warning("network_cpus=%s: malformed cpu list\n", - str); + pr_warn("network_cpus=%s: malformed cpu list\n", str); } else { /* Remove dedicated cpus. */ @@ -2472,12 +2405,10 @@ if (cpumask_empty(&network_cpus_map)) { - pr_warning("Ignoring network_cpus='%s'.\n", - str); + pr_warn("Ignoring network_cpus='%s'\n", str); } else { - char buf[1024]; - cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map); - pr_info("Linux network CPUs: %s\n", buf); + pr_info("Linux network CPUs: %*pbl\n", + cpumask_pr_args(&network_cpus_map)); network_cpus_used = true; } }