Added a counter rx_noskb_drop for failure to allocate an skb.
Summed the per-channel rx_nodesc_trunc counters earlier so that they can
 be included in rx_dropped.
Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
        { NULL, 64, 8 * MC_CMD_MAC_ ## mcdi_name }
 #define EF10_OTHER_STAT(ext_name)                              \
        [EF10_STAT_ ## ext_name] = { #ext_name, 0, 0 }
+#define GENERIC_SW_STAT(ext_name)                              \
+       [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 }
 
 static const struct efx_hw_stat_desc efx_ef10_stat_desc[EF10_STAT_COUNT] = {
        EF10_DMA_STAT(tx_bytes, TX_BYTES),
        EF10_DMA_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS),
        EF10_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS),
        EF10_DMA_STAT(rx_nodesc_drops, RX_NODESC_DROPS),
+       GENERIC_SW_STAT(rx_nodesc_trunc),
+       GENERIC_SW_STAT(rx_noskb_drops),
        EF10_DMA_STAT(rx_pm_trunc_bb_overflow, PM_TRUNC_BB_OVERFLOW),
        EF10_DMA_STAT(rx_pm_discard_bb_overflow, PM_DISCARD_BB_OVERFLOW),
        EF10_DMA_STAT(rx_pm_trunc_vfifo_full, PM_TRUNC_VFIFO_FULL),
                               (1ULL << EF10_STAT_rx_gtjumbo) |         \
                               (1ULL << EF10_STAT_rx_bad_gtjumbo) |     \
                               (1ULL << EF10_STAT_rx_overflow) |        \
-                              (1ULL << EF10_STAT_rx_nodesc_drops))
+                              (1ULL << EF10_STAT_rx_nodesc_drops) |    \
+                              (1ULL << GENERIC_STAT_rx_nodesc_trunc) | \
+                              (1ULL << GENERIC_STAT_rx_noskb_drops))
 
 /* These statistics are only provided by the 10G MAC.  For a 10G/40G
  * switchable port we do not expose these because they might not
                stats[EF10_STAT_rx_bytes_minus_good_bytes];
        efx_update_diff_stat(&stats[EF10_STAT_rx_bad_bytes],
                             stats[EF10_STAT_rx_bytes_minus_good_bytes]);
-
+       efx_update_sw_stats(efx, stats);
        return 0;
 }
 
                core_stats->tx_packets = stats[EF10_STAT_tx_packets];
                core_stats->rx_bytes = stats[EF10_STAT_rx_bytes];
                core_stats->tx_bytes = stats[EF10_STAT_tx_bytes];
-               core_stats->rx_dropped = stats[EF10_STAT_rx_nodesc_drops];
+               core_stats->rx_dropped = stats[EF10_STAT_rx_nodesc_drops] +
+                                        stats[GENERIC_STAT_rx_nodesc_trunc] +
+                                        stats[GENERIC_STAT_rx_noskb_drops];
                core_stats->multicast = stats[EF10_STAT_rx_multicast];
                core_stats->rx_length_errors =
                        stats[EF10_STAT_rx_gtjumbo] +
 
        }
 }
 
+void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
+{
+       u64 n_rx_nodesc_trunc = 0;
+       struct efx_channel *channel;
+
+       efx_for_each_channel(channel, efx)
+               n_rx_nodesc_trunc += channel->n_rx_nodesc_trunc;
+       stats[GENERIC_STAT_rx_nodesc_trunc] = n_rx_nodesc_trunc;
+       stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
+}
+
 /**************************************************************************
  *
  * PCI interface
 
 int efx_port_dummy_op_int(struct efx_nic *efx);
 void efx_port_dummy_op_void(struct efx_nic *efx);
 
+/* Update the generic software stats in the passed stats array */
+void efx_update_sw_stats(struct efx_nic *efx, u64 *stats);
+
 /* MTD */
 #ifdef CONFIG_SFC_MTD
 int efx_mtd_add(struct efx_nic *efx, struct efx_mtd_partition *parts,
 
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
-       EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_nodesc_trunc),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events),
        EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets),
 };
 
          hw_name ## _ ## offset }
 #define FALCON_OTHER_STAT(ext_name)                                    \
        [FALCON_STAT_ ## ext_name] = { #ext_name, 0, 0 }
+#define GENERIC_SW_STAT(ext_name)                              \
+       [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 }
 
 static const struct efx_hw_stat_desc falcon_stat_desc[FALCON_STAT_COUNT] = {
        FALCON_DMA_STAT(tx_bytes, XgTxOctets),
        FALCON_DMA_STAT(rx_length_error, XgRxLengthError),
        FALCON_DMA_STAT(rx_internal_error, XgRxInternalMACError),
        FALCON_OTHER_STAT(rx_nodesc_drop_cnt),
+       GENERIC_SW_STAT(rx_nodesc_trunc),
+       GENERIC_SW_STAT(rx_noskb_drops),
 };
 static const unsigned long falcon_stat_mask[] = {
        [0 ... BITS_TO_LONGS(FALCON_STAT_COUNT) - 1] = ~0UL,
                                     stats[FALCON_STAT_rx_bytes] -
                                     stats[FALCON_STAT_rx_good_bytes] -
                                     stats[FALCON_STAT_rx_control] * 64);
+               efx_update_sw_stats(efx, stats);
        }
 
        if (full_stats)
                core_stats->tx_packets = stats[FALCON_STAT_tx_packets];
                core_stats->rx_bytes = stats[FALCON_STAT_rx_bytes];
                core_stats->tx_bytes = stats[FALCON_STAT_tx_bytes];
-               core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt];
+               core_stats->rx_dropped = stats[FALCON_STAT_rx_nodesc_drop_cnt] +
+                                        stats[GENERIC_STAT_rx_nodesc_trunc] +
+                                        stats[GENERIC_STAT_rx_noskb_drops];
                core_stats->multicast = stats[FALCON_STAT_rx_multicast];
                core_stats->rx_length_errors =
                        stats[FALCON_STAT_rx_gtjumbo] +
 
  *     interrupt has occurred.
  * @stats_lock: Statistics update lock. Must be held when calling
  *     efx_nic_type::{update,start,stop}_stats.
+ * @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb
  *
  * This is stored in the private area of the &struct net_device.
  */
        spinlock_t biu_lock;
        int last_irq_cpu;
        spinlock_t stats_lock;
+       atomic_t n_rx_noskb_drops;
 };
 
 static inline int efx_dev_registered(struct efx_nic *efx)
 
 /* Size and alignment of buffer table entries (same) */
 #define EFX_BUF_SIZE   EFX_PAGE_SIZE
 
+/* NIC-generic software stats */
+enum {
+       GENERIC_STAT_rx_noskb_drops,
+       GENERIC_STAT_rx_nodesc_trunc,
+       GENERIC_STAT_COUNT
+};
+
 /**
  * struct falcon_board_type - board operations and type information
  * @id: Board type id, as found in NVRAM
 }
 
 enum {
-       FALCON_STAT_tx_bytes,
+       FALCON_STAT_tx_bytes = GENERIC_STAT_COUNT,
        FALCON_STAT_tx_packets,
        FALCON_STAT_tx_pause,
        FALCON_STAT_tx_control,
 }
 
 enum {
-       SIENA_STAT_tx_bytes,
+       SIENA_STAT_tx_bytes = GENERIC_STAT_COUNT,
        SIENA_STAT_tx_good_bytes,
        SIENA_STAT_tx_bad_bytes,
        SIENA_STAT_tx_packets,
 };
 
 enum {
-       EF10_STAT_tx_bytes,
+       EF10_STAT_tx_bytes = GENERIC_STAT_COUNT,
        EF10_STAT_tx_packets,
        EF10_STAT_tx_pause,
        EF10_STAT_tx_control,
 
        skb = netdev_alloc_skb(efx->net_dev,
                               efx->rx_ip_align + efx->rx_prefix_size +
                               hdr_len);
-       if (unlikely(skb == NULL))
+       if (unlikely(skb == NULL)) {
+               atomic_inc(&efx->n_rx_noskb_drops);
                return NULL;
+       }
 
        EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
 
 
        { #ext_name, 64, 8 * MC_CMD_MAC_ ## mcdi_name }
 #define SIENA_OTHER_STAT(ext_name)                             \
        [SIENA_STAT_ ## ext_name] = { #ext_name, 0, 0 }
+#define GENERIC_SW_STAT(ext_name)                              \
+       [GENERIC_STAT_ ## ext_name] = { #ext_name, 0, 0 }
 
 static const struct efx_hw_stat_desc siena_stat_desc[SIENA_STAT_COUNT] = {
        SIENA_DMA_STAT(tx_bytes, TX_BYTES),
        SIENA_DMA_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS),
        SIENA_DMA_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS),
        SIENA_DMA_STAT(rx_nodesc_drop_cnt, RX_NODESC_DROPS),
+       GENERIC_SW_STAT(rx_nodesc_trunc),
+       GENERIC_SW_STAT(rx_noskb_drops),
 };
 static const unsigned long siena_stat_mask[] = {
        [0 ... BITS_TO_LONGS(SIENA_STAT_COUNT) - 1] = ~0UL,
        efx_update_diff_stat(&stats[SIENA_STAT_rx_good_bytes],
                             stats[SIENA_STAT_rx_bytes] -
                             stats[SIENA_STAT_rx_bad_bytes]);
+       efx_update_sw_stats(efx, stats);
        return 0;
 }
 
                core_stats->tx_packets = stats[SIENA_STAT_tx_packets];
                core_stats->rx_bytes = stats[SIENA_STAT_rx_bytes];
                core_stats->tx_bytes = stats[SIENA_STAT_tx_bytes];
-               core_stats->rx_dropped = stats[SIENA_STAT_rx_nodesc_drop_cnt];
+               core_stats->rx_dropped = stats[SIENA_STAT_rx_nodesc_drop_cnt] +
+                                        stats[GENERIC_STAT_rx_nodesc_trunc] +
+                                        stats[GENERIC_STAT_rx_noskb_drops];
                core_stats->multicast = stats[SIENA_STAT_rx_multicast];
                core_stats->collisions = stats[SIENA_STAT_tx_collision];
                core_stats->rx_length_errors =