1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 /* Copyright 2014-2016 Freescale Semiconductor Inc. 3 * Copyright 2016 NXP 4 */ 5 6 #include <linux/net_tstamp.h> 7 8 #include "dpni.h" /* DPNI_LINK_OPT_* */ 9 #include "dpaa2-eth.h" 10 11 /* To be kept in sync with DPNI statistics */ 12 static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = { 13 "[hw] rx frames", 14 "[hw] rx bytes", 15 "[hw] rx mcast frames", 16 "[hw] rx mcast bytes", 17 "[hw] rx bcast frames", 18 "[hw] rx bcast bytes", 19 "[hw] tx frames", 20 "[hw] tx bytes", 21 "[hw] tx mcast frames", 22 "[hw] tx mcast bytes", 23 "[hw] tx bcast frames", 24 "[hw] tx bcast bytes", 25 "[hw] rx filtered frames", 26 "[hw] rx discarded frames", 27 "[hw] rx nobuffer discards", 28 "[hw] tx discarded frames", 29 "[hw] tx confirmed frames", 30 }; 31 32 #define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats) 33 34 static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = { 35 /* per-cpu stats */ 36 "[drv] tx conf frames", 37 "[drv] tx conf bytes", 38 "[drv] tx sg frames", 39 "[drv] tx sg bytes", 40 "[drv] tx realloc frames", 41 "[drv] rx sg frames", 42 "[drv] rx sg bytes", 43 "[drv] enqueue portal busy", 44 /* Channel stats */ 45 "[drv] dequeue portal busy", 46 "[drv] channel pull errors", 47 "[drv] cdan", 48 }; 49 50 #define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras) 51 52 static void dpaa2_eth_get_drvinfo(struct net_device *net_dev, 53 struct ethtool_drvinfo *drvinfo) 54 { 55 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 56 57 strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); 58 59 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 60 "%u.%u", priv->dpni_ver_major, priv->dpni_ver_minor); 61 62 strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), 63 sizeof(drvinfo->bus_info)); 64 } 65 66 static int 67 dpaa2_eth_get_link_ksettings(struct net_device *net_dev, 68 struct ethtool_link_ksettings *link_settings) 69 { 70 struct dpni_link_state state = {0}; 71 int err = 0; 72 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 73 74 err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); 75 if (err) { 76 netdev_err(net_dev, "ERROR %d getting link state\n", err); 77 goto out; 78 } 79 80 /* At the moment, we have no way of interrogating the DPMAC 81 * from the DPNI side - and for that matter there may exist 82 * no DPMAC at all. So for now we just don't report anything 83 * beyond the DPNI attributes. 84 */ 85 if (state.options & DPNI_LINK_OPT_AUTONEG) 86 link_settings->base.autoneg = AUTONEG_ENABLE; 87 if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX)) 88 link_settings->base.duplex = DUPLEX_FULL; 89 link_settings->base.speed = state.rate; 90 91 out: 92 return err; 93 } 94 95 #define DPNI_DYNAMIC_LINK_SET_VER_MAJOR 7 96 #define DPNI_DYNAMIC_LINK_SET_VER_MINOR 1 97 static int 98 dpaa2_eth_set_link_ksettings(struct net_device *net_dev, 99 const struct ethtool_link_ksettings *link_settings) 100 { 101 struct dpni_link_cfg cfg = {0}; 102 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 103 int err = 0; 104 105 /* If using an older MC version, the DPNI must be down 106 * in order to be able to change link settings. Taking steps to let 107 * the user know that. 108 */ 109 if (dpaa2_eth_cmp_dpni_ver(priv, DPNI_DYNAMIC_LINK_SET_VER_MAJOR, 110 DPNI_DYNAMIC_LINK_SET_VER_MINOR) < 0) { 111 if (netif_running(net_dev)) { 112 netdev_info(net_dev, "Interface must be brought down first.\n"); 113 return -EACCES; 114 } 115 } 116 117 cfg.rate = link_settings->base.speed; 118 if (link_settings->base.autoneg == AUTONEG_ENABLE) 119 cfg.options |= DPNI_LINK_OPT_AUTONEG; 120 else 121 cfg.options &= ~DPNI_LINK_OPT_AUTONEG; 122 if (link_settings->base.duplex == DUPLEX_HALF) 123 cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX; 124 else 125 cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX; 126 127 err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); 128 if (err) 129 /* ethtool will be loud enough if we return an error; no point 130 * in putting our own error message on the console by default 131 */ 132 netdev_dbg(net_dev, "ERROR %d setting link cfg\n", err); 133 134 return err; 135 } 136 137 static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, 138 u8 *data) 139 { 140 u8 *p = data; 141 int i; 142 143 switch (stringset) { 144 case ETH_SS_STATS: 145 for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) { 146 strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN); 147 p += ETH_GSTRING_LEN; 148 } 149 for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) { 150 strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); 151 p += ETH_GSTRING_LEN; 152 } 153 break; 154 } 155 } 156 157 static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset) 158 { 159 switch (sset) { 160 case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ 161 return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS; 162 default: 163 return -EOPNOTSUPP; 164 } 165 } 166 167 /** Fill in hardware counters, as returned by MC. 168 */ 169 static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, 170 struct ethtool_stats *stats, 171 u64 *data) 172 { 173 int i = 0; 174 int j, k, err; 175 int num_cnt; 176 union dpni_statistics dpni_stats; 177 u64 cdan = 0; 178 u64 portal_busy = 0, pull_err = 0; 179 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 180 struct dpaa2_eth_drv_stats *extras; 181 struct dpaa2_eth_ch_stats *ch_stats; 182 183 memset(data, 0, 184 sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS)); 185 186 /* Print standard counters, from DPNI statistics */ 187 for (j = 0; j <= 2; j++) { 188 err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, 189 j, &dpni_stats); 190 if (err != 0) 191 netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j); 192 switch (j) { 193 case 0: 194 num_cnt = sizeof(dpni_stats.page_0) / sizeof(u64); 195 break; 196 case 1: 197 num_cnt = sizeof(dpni_stats.page_1) / sizeof(u64); 198 break; 199 case 2: 200 num_cnt = sizeof(dpni_stats.page_2) / sizeof(u64); 201 break; 202 } 203 for (k = 0; k < num_cnt; k++) 204 *(data + i++) = dpni_stats.raw.counter[k]; 205 } 206 207 /* Print per-cpu extra stats */ 208 for_each_online_cpu(k) { 209 extras = per_cpu_ptr(priv->percpu_extras, k); 210 for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++) 211 *((__u64 *)data + i + j) += *((__u64 *)extras + j); 212 } 213 i += j; 214 215 for (j = 0; j < priv->num_channels; j++) { 216 ch_stats = &priv->channel[j]->stats; 217 cdan += ch_stats->cdan; 218 portal_busy += ch_stats->dequeue_portal_busy; 219 pull_err += ch_stats->pull_err; 220 } 221 222 *(data + i++) = portal_busy; 223 *(data + i++) = pull_err; 224 *(data + i++) = cdan; 225 } 226 227 static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, 228 struct ethtool_rxnfc *rxnfc, u32 *rule_locs) 229 { 230 struct dpaa2_eth_priv *priv = netdev_priv(net_dev); 231 232 switch (rxnfc->cmd) { 233 case ETHTOOL_GRXFH: 234 /* we purposely ignore cmd->flow_type for now, because the 235 * classifier only supports a single set of fields for all 236 * protocols 237 */ 238 rxnfc->data = priv->rx_hash_fields; 239 break; 240 case ETHTOOL_GRXRINGS: 241 rxnfc->data = dpaa2_eth_queue_count(priv); 242 break; 243 default: 244 return -EOPNOTSUPP; 245 } 246 247 return 0; 248 } 249 250 int dpaa2_phc_index = -1; 251 EXPORT_SYMBOL(dpaa2_phc_index); 252 253 static int dpaa2_eth_get_ts_info(struct net_device *dev, 254 struct ethtool_ts_info *info) 255 { 256 info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | 257 SOF_TIMESTAMPING_RX_HARDWARE | 258 SOF_TIMESTAMPING_RAW_HARDWARE; 259 260 info->phc_index = dpaa2_phc_index; 261 262 info->tx_types = (1 << HWTSTAMP_TX_OFF) | 263 (1 << HWTSTAMP_TX_ON); 264 265 info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | 266 (1 << HWTSTAMP_FILTER_ALL); 267 return 0; 268 } 269 270 const struct ethtool_ops dpaa2_ethtool_ops = { 271 .get_drvinfo = dpaa2_eth_get_drvinfo, 272 .get_link = ethtool_op_get_link, 273 .get_link_ksettings = dpaa2_eth_get_link_ksettings, 274 .set_link_ksettings = dpaa2_eth_set_link_ksettings, 275 .get_sset_count = dpaa2_eth_get_sset_count, 276 .get_ethtool_stats = dpaa2_eth_get_ethtool_stats, 277 .get_strings = dpaa2_eth_get_strings, 278 .get_rxnfc = dpaa2_eth_get_rxnfc, 279 .get_ts_info = dpaa2_eth_get_ts_info, 280 }; 281