This source file includes following definitions.
- ethsw_get_drvinfo
- ethsw_get_link_ksettings
- ethsw_set_link_ksettings
- ethsw_ethtool_get_sset_count
- ethsw_ethtool_get_strings
- ethsw_ethtool_get_stats
1
2
3
4
5
6
7
8
9
10 #include "ethsw.h"
11
12 static struct {
13 enum dpsw_counter id;
14 char name[ETH_GSTRING_LEN];
15 } ethsw_ethtool_counters[] = {
16 {DPSW_CNT_ING_FRAME, "rx frames"},
17 {DPSW_CNT_ING_BYTE, "rx bytes"},
18 {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"},
19 {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"},
20 {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"},
21 {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"},
22 {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"},
23 {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"},
24 {DPSW_CNT_EGR_FRAME, "tx frames"},
25 {DPSW_CNT_EGR_BYTE, "tx bytes"},
26 {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"},
27
28 };
29
30 #define ETHSW_NUM_COUNTERS ARRAY_SIZE(ethsw_ethtool_counters)
31
32 static void ethsw_get_drvinfo(struct net_device *netdev,
33 struct ethtool_drvinfo *drvinfo)
34 {
35 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
36 u16 version_major, version_minor;
37 int err;
38
39 strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
40
41 err = dpsw_get_api_version(port_priv->ethsw_data->mc_io, 0,
42 &version_major,
43 &version_minor);
44 if (err)
45 strlcpy(drvinfo->fw_version, "N/A",
46 sizeof(drvinfo->fw_version));
47 else
48 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
49 "%u.%u", version_major, version_minor);
50
51 strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent),
52 sizeof(drvinfo->bus_info));
53 }
54
55 static int
56 ethsw_get_link_ksettings(struct net_device *netdev,
57 struct ethtool_link_ksettings *link_ksettings)
58 {
59 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
60 struct dpsw_link_state state = {0};
61 int err = 0;
62
63 err = dpsw_if_get_link_state(port_priv->ethsw_data->mc_io, 0,
64 port_priv->ethsw_data->dpsw_handle,
65 port_priv->idx,
66 &state);
67 if (err) {
68 netdev_err(netdev, "ERROR %d getting link state\n", err);
69 goto out;
70 }
71
72
73
74
75
76 if (state.options & DPSW_LINK_OPT_AUTONEG)
77 link_ksettings->base.autoneg = AUTONEG_ENABLE;
78 if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX))
79 link_ksettings->base.duplex = DUPLEX_FULL;
80 link_ksettings->base.speed = state.rate;
81
82 out:
83 return err;
84 }
85
86 static int
87 ethsw_set_link_ksettings(struct net_device *netdev,
88 const struct ethtool_link_ksettings *link_ksettings)
89 {
90 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
91 struct ethsw_core *ethsw = port_priv->ethsw_data;
92 struct dpsw_link_cfg cfg = {0};
93 bool if_running;
94 int err = 0, ret;
95
96
97 if_running = netif_running(netdev);
98 if (if_running) {
99 err = dpsw_if_disable(ethsw->mc_io, 0,
100 ethsw->dpsw_handle,
101 port_priv->idx);
102 if (err) {
103 netdev_err(netdev, "dpsw_if_disable err %d\n", err);
104 return err;
105 }
106 }
107
108 cfg.rate = link_ksettings->base.speed;
109 if (link_ksettings->base.autoneg == AUTONEG_ENABLE)
110 cfg.options |= DPSW_LINK_OPT_AUTONEG;
111 else
112 cfg.options &= ~DPSW_LINK_OPT_AUTONEG;
113 if (link_ksettings->base.duplex == DUPLEX_HALF)
114 cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX;
115 else
116 cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX;
117
118 err = dpsw_if_set_link_cfg(port_priv->ethsw_data->mc_io, 0,
119 port_priv->ethsw_data->dpsw_handle,
120 port_priv->idx,
121 &cfg);
122
123 if (if_running) {
124 ret = dpsw_if_enable(ethsw->mc_io, 0,
125 ethsw->dpsw_handle,
126 port_priv->idx);
127 if (ret) {
128 netdev_err(netdev, "dpsw_if_enable err %d\n", ret);
129 return ret;
130 }
131 }
132 return err;
133 }
134
135 static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset)
136 {
137 switch (sset) {
138 case ETH_SS_STATS:
139 return ETHSW_NUM_COUNTERS;
140 default:
141 return -EOPNOTSUPP;
142 }
143 }
144
145 static void ethsw_ethtool_get_strings(struct net_device *netdev,
146 u32 stringset, u8 *data)
147 {
148 int i;
149
150 switch (stringset) {
151 case ETH_SS_STATS:
152 for (i = 0; i < ETHSW_NUM_COUNTERS; i++)
153 memcpy(data + i * ETH_GSTRING_LEN,
154 ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN);
155 break;
156 }
157 }
158
159 static void ethsw_ethtool_get_stats(struct net_device *netdev,
160 struct ethtool_stats *stats,
161 u64 *data)
162 {
163 struct ethsw_port_priv *port_priv = netdev_priv(netdev);
164 int i, err;
165
166 for (i = 0; i < ETHSW_NUM_COUNTERS; i++) {
167 err = dpsw_if_get_counter(port_priv->ethsw_data->mc_io, 0,
168 port_priv->ethsw_data->dpsw_handle,
169 port_priv->idx,
170 ethsw_ethtool_counters[i].id,
171 &data[i]);
172 if (err)
173 netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n",
174 ethsw_ethtool_counters[i].name, err);
175 }
176 }
177
178 const struct ethtool_ops ethsw_port_ethtool_ops = {
179 .get_drvinfo = ethsw_get_drvinfo,
180 .get_link = ethtool_op_get_link,
181 .get_link_ksettings = ethsw_get_link_ksettings,
182 .set_link_ksettings = ethsw_set_link_ksettings,
183 .get_strings = ethsw_ethtool_get_strings,
184 .get_ethtool_stats = ethsw_ethtool_get_stats,
185 .get_sset_count = ethsw_ethtool_get_sset_count,
186 };