|
@@ -36,6 +36,42 @@
|
|
|
#include "dpaa_eth.h"
|
|
|
#include "mac.h"
|
|
|
|
|
|
+static const char dpaa_stats_percpu[][ETH_GSTRING_LEN] = {
|
|
|
+ "interrupts",
|
|
|
+ "rx packets",
|
|
|
+ "tx packets",
|
|
|
+ "tx confirm",
|
|
|
+ "tx S/G",
|
|
|
+ "tx error",
|
|
|
+ "rx error",
|
|
|
+};
|
|
|
+
|
|
|
+static char dpaa_stats_global[][ETH_GSTRING_LEN] = {
|
|
|
+ /* dpa rx errors */
|
|
|
+ "rx dma error",
|
|
|
+ "rx frame physical error",
|
|
|
+ "rx frame size error",
|
|
|
+ "rx header error",
|
|
|
+
|
|
|
+ /* demultiplexing errors */
|
|
|
+ "qman cg_tdrop",
|
|
|
+ "qman wred",
|
|
|
+ "qman error cond",
|
|
|
+ "qman early window",
|
|
|
+ "qman late window",
|
|
|
+ "qman fq tdrop",
|
|
|
+ "qman fq retired",
|
|
|
+ "qman orp disabled",
|
|
|
+
|
|
|
+ /* congestion related stats */
|
|
|
+ "congestion time (ms)",
|
|
|
+ "entered congestion",
|
|
|
+ "congested (0/1)"
|
|
|
+};
|
|
|
+
|
|
|
+#define DPAA_STATS_PERCPU_LEN ARRAY_SIZE(dpaa_stats_percpu)
|
|
|
+#define DPAA_STATS_GLOBAL_LEN ARRAY_SIZE(dpaa_stats_global)
|
|
|
+
|
|
|
static int dpaa_get_settings(struct net_device *net_dev,
|
|
|
struct ethtool_cmd *et_cmd)
|
|
|
{
|
|
@@ -205,6 +241,166 @@ static int dpaa_set_pauseparam(struct net_device *net_dev,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+static int dpaa_get_sset_count(struct net_device *net_dev, int type)
|
|
|
+{
|
|
|
+ unsigned int total_stats, num_stats;
|
|
|
+
|
|
|
+ num_stats = num_online_cpus() + 1;
|
|
|
+ total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM) +
|
|
|
+ DPAA_STATS_GLOBAL_LEN;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case ETH_SS_STATS:
|
|
|
+ return total_stats;
|
|
|
+ default:
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus,
|
|
|
+ int crr_cpu, u64 *bp_count, u64 *data)
|
|
|
+{
|
|
|
+ int num_values = num_cpus + 1;
|
|
|
+ int crr = 0, j;
|
|
|
+
|
|
|
+ /* update current CPU's stats and also add them to the total values */
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->in_interrupt;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->in_interrupt;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_packets;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_packets;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_packets;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_packets;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->tx_confirm;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->tx_confirm;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->tx_frag_skbuffs;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->tx_frag_skbuffs;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_errors;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_errors;
|
|
|
+
|
|
|
+ data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors;
|
|
|
+ data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors;
|
|
|
+
|
|
|
+ for (j = 0; j < DPAA_BPS_NUM; j++) {
|
|
|
+ data[crr * num_values + crr_cpu] = bp_count[j];
|
|
|
+ data[crr++ * num_values + num_cpus] += bp_count[j];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void dpaa_get_ethtool_stats(struct net_device *net_dev,
|
|
|
+ struct ethtool_stats *stats, u64 *data)
|
|
|
+{
|
|
|
+ u64 bp_count[DPAA_BPS_NUM], cg_time, cg_num;
|
|
|
+ struct dpaa_percpu_priv *percpu_priv;
|
|
|
+ struct dpaa_rx_errors rx_errors;
|
|
|
+ unsigned int num_cpus, offset;
|
|
|
+ struct dpaa_ern_cnt ern_cnt;
|
|
|
+ struct dpaa_bp *dpaa_bp;
|
|
|
+ struct dpaa_priv *priv;
|
|
|
+ int total_stats, i, j;
|
|
|
+ bool cg_status;
|
|
|
+
|
|
|
+ total_stats = dpaa_get_sset_count(net_dev, ETH_SS_STATS);
|
|
|
+ priv = netdev_priv(net_dev);
|
|
|
+ num_cpus = num_online_cpus();
|
|
|
+
|
|
|
+ memset(&bp_count, 0, sizeof(bp_count));
|
|
|
+ memset(&rx_errors, 0, sizeof(struct dpaa_rx_errors));
|
|
|
+ memset(&ern_cnt, 0, sizeof(struct dpaa_ern_cnt));
|
|
|
+ memset(data, 0, total_stats * sizeof(u64));
|
|
|
+
|
|
|
+ for_each_online_cpu(i) {
|
|
|
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
|
|
|
+ for (j = 0; j < DPAA_BPS_NUM; j++) {
|
|
|
+ dpaa_bp = priv->dpaa_bps[j];
|
|
|
+ if (!dpaa_bp->percpu_count)
|
|
|
+ continue;
|
|
|
+ bp_count[j] = *(per_cpu_ptr(dpaa_bp->percpu_count, i));
|
|
|
+ }
|
|
|
+ rx_errors.dme += percpu_priv->rx_errors.dme;
|
|
|
+ rx_errors.fpe += percpu_priv->rx_errors.fpe;
|
|
|
+ rx_errors.fse += percpu_priv->rx_errors.fse;
|
|
|
+ rx_errors.phe += percpu_priv->rx_errors.phe;
|
|
|
+
|
|
|
+ ern_cnt.cg_tdrop += percpu_priv->ern_cnt.cg_tdrop;
|
|
|
+ ern_cnt.wred += percpu_priv->ern_cnt.wred;
|
|
|
+ ern_cnt.err_cond += percpu_priv->ern_cnt.err_cond;
|
|
|
+ ern_cnt.early_window += percpu_priv->ern_cnt.early_window;
|
|
|
+ ern_cnt.late_window += percpu_priv->ern_cnt.late_window;
|
|
|
+ ern_cnt.fq_tdrop += percpu_priv->ern_cnt.fq_tdrop;
|
|
|
+ ern_cnt.fq_retired += percpu_priv->ern_cnt.fq_retired;
|
|
|
+ ern_cnt.orp_zero += percpu_priv->ern_cnt.orp_zero;
|
|
|
+
|
|
|
+ copy_stats(percpu_priv, num_cpus, i, bp_count, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM);
|
|
|
+ memcpy(data + offset, &rx_errors, sizeof(struct dpaa_rx_errors));
|
|
|
+
|
|
|
+ offset += sizeof(struct dpaa_rx_errors) / sizeof(u64);
|
|
|
+ memcpy(data + offset, &ern_cnt, sizeof(struct dpaa_ern_cnt));
|
|
|
+
|
|
|
+ /* gather congestion related counters */
|
|
|
+ cg_num = 0;
|
|
|
+ cg_status = 0;
|
|
|
+ cg_time = jiffies_to_msecs(priv->cgr_data.congested_jiffies);
|
|
|
+ if (qman_query_cgr_congested(&priv->cgr_data.cgr, &cg_status) == 0) {
|
|
|
+ cg_num = priv->cgr_data.cgr_congested_count;
|
|
|
+
|
|
|
+ /* reset congestion stats (like QMan API does */
|
|
|
+ priv->cgr_data.congested_jiffies = 0;
|
|
|
+ priv->cgr_data.cgr_congested_count = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ offset += sizeof(struct dpaa_ern_cnt) / sizeof(u64);
|
|
|
+ data[offset++] = cg_time;
|
|
|
+ data[offset++] = cg_num;
|
|
|
+ data[offset++] = cg_status;
|
|
|
+}
|
|
|
+
|
|
|
+static void dpaa_get_strings(struct net_device *net_dev, u32 stringset,
|
|
|
+ u8 *data)
|
|
|
+{
|
|
|
+ unsigned int i, j, num_cpus, size;
|
|
|
+ char string_cpu[ETH_GSTRING_LEN];
|
|
|
+ u8 *strings;
|
|
|
+
|
|
|
+ memset(string_cpu, 0, sizeof(string_cpu));
|
|
|
+ strings = data;
|
|
|
+ num_cpus = num_online_cpus();
|
|
|
+ size = DPAA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN;
|
|
|
+
|
|
|
+ for (i = 0; i < DPAA_STATS_PERCPU_LEN; i++) {
|
|
|
+ for (j = 0; j < num_cpus; j++) {
|
|
|
+ snprintf(string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]",
|
|
|
+ dpaa_stats_percpu[i], j);
|
|
|
+ memcpy(strings, string_cpu, ETH_GSTRING_LEN);
|
|
|
+ strings += ETH_GSTRING_LEN;
|
|
|
+ }
|
|
|
+ snprintf(string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]",
|
|
|
+ dpaa_stats_percpu[i]);
|
|
|
+ memcpy(strings, string_cpu, ETH_GSTRING_LEN);
|
|
|
+ strings += ETH_GSTRING_LEN;
|
|
|
+ }
|
|
|
+ for (i = 0; i < DPAA_BPS_NUM; i++) {
|
|
|
+ for (j = 0; j < num_cpus; j++) {
|
|
|
+ snprintf(string_cpu, ETH_GSTRING_LEN,
|
|
|
+ "bpool %c [CPU %d]", 'a' + i, j);
|
|
|
+ memcpy(strings, string_cpu, ETH_GSTRING_LEN);
|
|
|
+ strings += ETH_GSTRING_LEN;
|
|
|
+ }
|
|
|
+ snprintf(string_cpu, ETH_GSTRING_LEN, "bpool %c [TOTAL]",
|
|
|
+ 'a' + i);
|
|
|
+ memcpy(strings, string_cpu, ETH_GSTRING_LEN);
|
|
|
+ strings += ETH_GSTRING_LEN;
|
|
|
+ }
|
|
|
+ memcpy(strings, dpaa_stats_global, size);
|
|
|
+}
|
|
|
+
|
|
|
const struct ethtool_ops dpaa_ethtool_ops = {
|
|
|
.get_settings = dpaa_get_settings,
|
|
|
.set_settings = dpaa_set_settings,
|
|
@@ -215,4 +411,7 @@ const struct ethtool_ops dpaa_ethtool_ops = {
|
|
|
.get_pauseparam = dpaa_get_pauseparam,
|
|
|
.set_pauseparam = dpaa_set_pauseparam,
|
|
|
.get_link = ethtool_op_get_link,
|
|
|
+ .get_sset_count = dpaa_get_sset_count,
|
|
|
+ .get_ethtool_stats = dpaa_get_ethtool_stats,
|
|
|
+ .get_strings = dpaa_get_strings,
|
|
|
};
|