0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/ethtool.h>
0011
0012 #include "dpaa2-switch.h"
0013
0014 static struct {
0015 enum dpsw_counter id;
0016 char name[ETH_GSTRING_LEN];
0017 } dpaa2_switch_ethtool_counters[] = {
0018 {DPSW_CNT_ING_FRAME, "[hw] rx frames"},
0019 {DPSW_CNT_ING_BYTE, "[hw] rx bytes"},
0020 {DPSW_CNT_ING_FLTR_FRAME, "[hw] rx filtered frames"},
0021 {DPSW_CNT_ING_FRAME_DISCARD, "[hw] rx discarded frames"},
0022 {DPSW_CNT_ING_BCAST_FRAME, "[hw] rx bcast frames"},
0023 {DPSW_CNT_ING_BCAST_BYTES, "[hw] rx bcast bytes"},
0024 {DPSW_CNT_ING_MCAST_FRAME, "[hw] rx mcast frames"},
0025 {DPSW_CNT_ING_MCAST_BYTE, "[hw] rx mcast bytes"},
0026 {DPSW_CNT_EGR_FRAME, "[hw] tx frames"},
0027 {DPSW_CNT_EGR_BYTE, "[hw] tx bytes"},
0028 {DPSW_CNT_EGR_FRAME_DISCARD, "[hw] tx discarded frames"},
0029 {DPSW_CNT_ING_NO_BUFF_DISCARD, "[hw] rx nobuffer discards"},
0030 };
0031
0032 #define DPAA2_SWITCH_NUM_COUNTERS ARRAY_SIZE(dpaa2_switch_ethtool_counters)
0033
0034 static void dpaa2_switch_get_drvinfo(struct net_device *netdev,
0035 struct ethtool_drvinfo *drvinfo)
0036 {
0037 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0038 u16 version_major, version_minor;
0039 int err;
0040
0041 strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
0042
0043 err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0,
0044 &version_major,
0045 &version_minor);
0046 if (err)
0047 strscpy(drvinfo->fw_version, "N/A",
0048 sizeof(drvinfo->fw_version));
0049 else
0050 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
0051 "%u.%u", version_major, version_minor);
0052
0053 strscpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
0054 sizeof(drvinfo->bus_info));
0055 }
0056
0057 static int
0058 dpaa2_switch_get_link_ksettings(struct net_device *netdev,
0059 struct ethtool_link_ksettings *link_ksettings)
0060 {
0061 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0062 struct dpsw_link_state state = {0};
0063 int err = 0;
0064
0065 if (dpaa2_switch_port_is_type_phy(port_priv))
0066 return phylink_ethtool_ksettings_get(port_priv->mac->phylink,
0067 link_ksettings);
0068
0069 err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
0070 port_priv->ethsw_data->dpsw_handle,
0071 port_priv->idx,
0072 &state);
0073 if (err) {
0074 netdev_err(netdev, "ERROR %d getting link state\n", err);
0075 goto out;
0076 }
0077
0078
0079
0080
0081
0082 if (state.options & DPSW_LINK_OPT_AUTONEG)
0083 link_ksettings->base.autoneg = AUTONEG_ENABLE;
0084 if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))
0085 link_ksettings->base.duplex = DUPLEX_FULL;
0086 link_ksettings->base.speed = state.rate;
0087
0088 out:
0089 return err;
0090 }
0091
0092 static int
0093 dpaa2_switch_set_link_ksettings(struct net_device *netdev,
0094 const struct ethtool_link_ksettings *link_ksettings)
0095 {
0096 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0097 struct ethsw_core *ethsw = port_priv->ethsw_data;
0098 struct dpsw_link_cfg cfg = {0};
0099 bool if_running;
0100 int err = 0, ret;
0101
0102 if (dpaa2_switch_port_is_type_phy(port_priv))
0103 return phylink_ethtool_ksettings_set(port_priv->mac->phylink,
0104 link_ksettings);
0105
0106
0107 if_running = netif_running(netdev);
0108 if (if_running) {
0109 err = dpsw_if_disable(ethsw->mc_io, 0,
0110 ethsw->dpsw_handle,
0111 port_priv->idx);
0112 if (err) {
0113 netdev_err(netdev, "dpsw_if_disable err %d\n", err);
0114 return err;
0115 }
0116 }
0117
0118 cfg.rate = link_ksettings->base.speed;
0119 if (link_ksettings->base.autoneg == AUTONEG_ENABLE)
0120 cfg.options |= DPSW_LINK_OPT_AUTONEG;
0121 else
0122 cfg.options &= ~DPSW_LINK_OPT_AUTONEG;
0123 if (link_ksettings->base.duplex == DUPLEX_HALF)
0124 cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;
0125 else
0126 cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;
0127
0128 err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,
0129 port_priv->ethsw_data->dpsw_handle,
0130 port_priv->idx,
0131 &cfg);
0132
0133 if (if_running) {
0134 ret = dpsw_if_enable(ethsw->mc_io, 0,
0135 ethsw->dpsw_handle,
0136 port_priv->idx);
0137 if (ret) {
0138 netdev_err(netdev, "dpsw_if_enable err %d\n", ret);
0139 return ret;
0140 }
0141 }
0142 return err;
0143 }
0144
0145 static int
0146 dpaa2_switch_ethtool_get_sset_count(struct net_device *netdev, int sset)
0147 {
0148 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0149 int num_ss_stats = DPAA2_SWITCH_NUM_COUNTERS;
0150
0151 switch (sset) {
0152 case ETH_SS_STATS:
0153 if (port_priv->mac)
0154 num_ss_stats += dpaa2_mac_get_sset_count();
0155 return num_ss_stats;
0156 default:
0157 return -EOPNOTSUPP;
0158 }
0159 }
0160
0161 static void dpaa2_switch_ethtool_get_strings(struct net_device *netdev,
0162 u32 stringset, u8 *data)
0163 {
0164 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0165 u8 *p = data;
0166 int i;
0167
0168 switch (stringset) {
0169 case ETH_SS_STATS:
0170 for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
0171 memcpy(p, dpaa2_switch_ethtool_counters[i].name,
0172 ETH_GSTRING_LEN);
0173 p += ETH_GSTRING_LEN;
0174 }
0175 if (port_priv->mac)
0176 dpaa2_mac_get_strings(p);
0177 break;
0178 }
0179 }
0180
0181 static void dpaa2_switch_ethtool_get_stats(struct net_device *netdev,
0182 struct ethtool_stats *stats,
0183 u64 *data)
0184 {
0185 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
0186 int i, err;
0187
0188 for (i = 0; i < DPAA2_SWITCH_NUM_COUNTERS; i++) {
0189 err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
0190 port_priv->ethsw_data->dpsw_handle,
0191 port_priv->idx,
0192 dpaa2_switch_ethtool_counters[i].id,
0193 &data[i]);
0194 if (err)
0195 netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
0196 dpaa2_switch_ethtool_counters[i].name, err);
0197 }
0198
0199 if (port_priv->mac)
0200 dpaa2_mac_get_ethtool_stats(port_priv->mac, data + i);
0201 }
0202
0203 const struct ethtool_ops dpaa2_switch_port_ethtool_ops = {
0204 .get_drvinfo = dpaa2_switch_get_drvinfo,
0205 .get_link = ethtool_op_get_link,
0206 .get_link_ksettings = dpaa2_switch_get_link_ksettings,
0207 .set_link_ksettings = dpaa2_switch_set_link_ksettings,
0208 .get_strings = dpaa2_switch_ethtool_get_strings,
0209 .get_ethtool_stats = dpaa2_switch_ethtool_get_stats,
0210 .get_sset_count = dpaa2_switch_ethtool_get_sset_count,
0211 };