Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Texas Instruments ICSSG Ethernet driver
  3 *
  4 * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/
  5 *
  6 */
  7
  8#include "icssg_prueth.h"
  9#include "icssg_stats.h"
 10
 11static void emac_get_drvinfo(struct net_device *ndev,
 12			     struct ethtool_drvinfo *info)
 13{
 14	struct prueth_emac *emac = netdev_priv(ndev);
 15	struct prueth *prueth = emac->prueth;
 16
 17	strscpy(info->driver, dev_driver_string(prueth->dev),
 18		sizeof(info->driver));
 19	strscpy(info->bus_info, dev_name(prueth->dev), sizeof(info->bus_info));
 20}
 21
 22static u32 emac_get_msglevel(struct net_device *ndev)
 23{
 24	struct prueth_emac *emac = netdev_priv(ndev);
 25
 26	return emac->msg_enable;
 27}
 28
 29static void emac_set_msglevel(struct net_device *ndev, u32 value)
 30{
 31	struct prueth_emac *emac = netdev_priv(ndev);
 32
 33	emac->msg_enable = value;
 34}
 35
 36static int emac_get_link_ksettings(struct net_device *ndev,
 37				   struct ethtool_link_ksettings *ecmd)
 38{
 39	return phy_ethtool_get_link_ksettings(ndev, ecmd);
 40}
 41
 42static int emac_set_link_ksettings(struct net_device *ndev,
 43				   const struct ethtool_link_ksettings *ecmd)
 44{
 45	return phy_ethtool_set_link_ksettings(ndev, ecmd);
 46}
 47
 48static int emac_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
 49{
 50	if (!ndev->phydev)
 51		return -EOPNOTSUPP;
 52
 53	return phy_ethtool_get_eee(ndev->phydev, edata);
 54}
 55
 56static int emac_set_eee(struct net_device *ndev, struct ethtool_keee *edata)
 57{
 58	if (!ndev->phydev)
 59		return -EOPNOTSUPP;
 60
 61	return phy_ethtool_set_eee(ndev->phydev, edata);
 62}
 63
 64static int emac_nway_reset(struct net_device *ndev)
 65{
 66	return phy_ethtool_nway_reset(ndev);
 67}
 68
 69static int emac_get_sset_count(struct net_device *ndev, int stringset)
 70{
 71	struct prueth_emac *emac = netdev_priv(ndev);
 72	switch (stringset) {
 73	case ETH_SS_STATS:
 74		if (emac->prueth->pa_stats)
 75			return ICSSG_NUM_ETHTOOL_STATS;
 76		else
 77			return ICSSG_NUM_ETHTOOL_STATS - ICSSG_NUM_PA_STATS;
 78	default:
 79		return -EOPNOTSUPP;
 80	}
 81}
 82
 83static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
 84{
 85	struct prueth_emac *emac = netdev_priv(ndev);
 86	u8 *p = data;
 87	int i;
 88
 89	switch (stringset) {
 90	case ETH_SS_STATS:
 91		for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
 92			if (!icssg_all_miig_stats[i].standard_stats)
 93				ethtool_puts(&p, icssg_all_miig_stats[i].name);
 94		if (emac->prueth->pa_stats)
 95			for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
 96				ethtool_puts(&p, icssg_all_pa_stats[i].name);
 97		break;
 98	default:
 99		break;
100	}
101}
102
103static void emac_get_ethtool_stats(struct net_device *ndev,
104				   struct ethtool_stats *stats, u64 *data)
105{
106	struct prueth_emac *emac = netdev_priv(ndev);
107	int i;
108
109	emac_update_hardware_stats(emac);
110
111	for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
112		if (!icssg_all_miig_stats[i].standard_stats)
113			*(data++) = emac->stats[i];
114
115	if (emac->prueth->pa_stats)
116		for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
117			*(data++) = emac->pa_stats[i];
118}
119
120static int emac_get_ts_info(struct net_device *ndev,
121			    struct kernel_ethtool_ts_info *info)
122{
123	struct prueth_emac *emac = netdev_priv(ndev);
124
125	info->so_timestamping =
126		SOF_TIMESTAMPING_TX_HARDWARE |
127		SOF_TIMESTAMPING_TX_SOFTWARE |
128		SOF_TIMESTAMPING_RX_HARDWARE |
129		SOF_TIMESTAMPING_RAW_HARDWARE;
130
131	info->phc_index = icss_iep_get_ptp_clock_idx(emac->iep);
132	info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
133	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL);
134
135	return 0;
136}
137
138static int emac_set_channels(struct net_device *ndev,
139			     struct ethtool_channels *ch)
140{
141	struct prueth_emac *emac = netdev_priv(ndev);
142
143	/* Check if interface is up. Can change the num queues when
144	 * the interface is down.
145	 */
146	if (netif_running(emac->ndev))
147		return -EBUSY;
148
149	emac->tx_ch_num = ch->tx_count;
150
151	if (emac->is_sr1)
152		emac->tx_ch_num++;
153
154	return 0;
155}
156
157static void emac_get_channels(struct net_device *ndev,
158			      struct ethtool_channels *ch)
159{
160	struct prueth_emac *emac = netdev_priv(ndev);
161
162	ch->max_rx = 1;
163	ch->max_tx = PRUETH_MAX_TX_QUEUES;
164
165	/* Disable multiple TX channels due to timeouts
166	 * when using more than one queue */
167	if (emac->is_sr1)
168		ch->max_tx = 1;
169
170	ch->rx_count = 1;
171	ch->tx_count = emac->tx_ch_num;
172
173	if (emac->is_sr1)
174		ch->tx_count--;
175}
176
177static const struct ethtool_rmon_hist_range emac_rmon_ranges[] = {
178	{    0,   64},
179	{   65,  128},
180	{  129,  256},
181	{  257,  512},
182	{  513, PRUETH_MAX_PKT_SIZE},
183	{}
184};
185
186static void emac_get_rmon_stats(struct net_device *ndev,
187				struct ethtool_rmon_stats *rmon_stats,
188				const struct ethtool_rmon_hist_range **ranges)
189{
190	struct prueth_emac *emac = netdev_priv(ndev);
191
192	*ranges = emac_rmon_ranges;
193
194	rmon_stats->undersize_pkts = emac_get_stat_by_name(emac, "rx_bucket1_frames") -
195				     emac_get_stat_by_name(emac, "rx_64B_frames");
196
197	rmon_stats->hist[0] = emac_get_stat_by_name(emac, "rx_bucket1_frames");
198	rmon_stats->hist[1] = emac_get_stat_by_name(emac, "rx_bucket2_frames");
199	rmon_stats->hist[2] = emac_get_stat_by_name(emac, "rx_bucket3_frames");
200	rmon_stats->hist[3] = emac_get_stat_by_name(emac, "rx_bucket4_frames");
201	rmon_stats->hist[4] = emac_get_stat_by_name(emac, "rx_bucket5_frames");
202
203	rmon_stats->hist_tx[0] = emac_get_stat_by_name(emac, "tx_bucket1_frames");
204	rmon_stats->hist_tx[1] = emac_get_stat_by_name(emac, "tx_bucket2_frames");
205	rmon_stats->hist_tx[2] = emac_get_stat_by_name(emac, "tx_bucket3_frames");
206	rmon_stats->hist_tx[3] = emac_get_stat_by_name(emac, "tx_bucket4_frames");
207	rmon_stats->hist_tx[4] = emac_get_stat_by_name(emac, "tx_bucket5_frames");
208}
209
210static int emac_get_coalesce(struct net_device *ndev,
211			     struct ethtool_coalesce *coal,
212			     struct kernel_ethtool_coalesce *kernel_coal,
213			     struct netlink_ext_ack *extack)
214{
215	struct prueth_emac *emac = netdev_priv(ndev);
216	struct prueth_tx_chn *tx_chn;
217
218	tx_chn = &emac->tx_chns[0];
219
220	coal->rx_coalesce_usecs = emac->rx_pace_timeout_ns / 1000;
221	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000;
222
223	return 0;
224}
225
226static int emac_get_per_queue_coalesce(struct net_device *ndev, u32 queue,
227				       struct ethtool_coalesce *coal)
228{
229	struct prueth_emac *emac = netdev_priv(ndev);
230	struct prueth_tx_chn *tx_chn;
231
232	if (queue >= PRUETH_MAX_TX_QUEUES)
233		return -EINVAL;
234
235	tx_chn = &emac->tx_chns[queue];
236
237	coal->tx_coalesce_usecs = tx_chn->tx_pace_timeout_ns / 1000;
238
239	return 0;
240}
241
242static int emac_set_coalesce(struct net_device *ndev,
243			     struct ethtool_coalesce *coal,
244			     struct kernel_ethtool_coalesce *kernel_coal,
245			     struct netlink_ext_ack *extack)
246{
247	struct prueth_emac *emac = netdev_priv(ndev);
248	struct prueth *prueth = emac->prueth;
249	struct prueth_tx_chn *tx_chn;
250
251	tx_chn = &emac->tx_chns[0];
252
253	if (coal->rx_coalesce_usecs &&
254	    coal->rx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {
255		dev_info(prueth->dev, "defaulting to min value of %dus for rx-usecs\n",
256			 ICSSG_MIN_COALESCE_USECS);
257		coal->rx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;
258	}
259
260	if (coal->tx_coalesce_usecs &&
261	    coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {
262		dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs\n",
263			 ICSSG_MIN_COALESCE_USECS);
264		coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;
265	}
266
267	emac->rx_pace_timeout_ns = coal->rx_coalesce_usecs * 1000;
268	tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000;
269
270	return 0;
271}
272
273static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
274				       struct ethtool_coalesce *coal)
275{
276	struct prueth_emac *emac = netdev_priv(ndev);
277	struct prueth *prueth = emac->prueth;
278	struct prueth_tx_chn *tx_chn;
279
280	if (queue >= PRUETH_MAX_TX_QUEUES)
281		return -EINVAL;
282
283	tx_chn = &emac->tx_chns[queue];
284
285	if (coal->tx_coalesce_usecs &&
286	    coal->tx_coalesce_usecs < ICSSG_MIN_COALESCE_USECS) {
287		dev_info(prueth->dev, "defaulting to min value of %dus for tx-usecs for tx-%u\n",
288			 ICSSG_MIN_COALESCE_USECS, queue);
289		coal->tx_coalesce_usecs = ICSSG_MIN_COALESCE_USECS;
290	}
291
292	tx_chn->tx_pace_timeout_ns = coal->tx_coalesce_usecs * 1000;
293
294	return 0;
295}
296
297const struct ethtool_ops icssg_ethtool_ops = {
298	.get_drvinfo = emac_get_drvinfo,
299	.get_msglevel = emac_get_msglevel,
300	.set_msglevel = emac_set_msglevel,
301	.get_sset_count = emac_get_sset_count,
302	.get_ethtool_stats = emac_get_ethtool_stats,
303	.get_strings = emac_get_strings,
304	.get_ts_info = emac_get_ts_info,
305	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
306				     ETHTOOL_COALESCE_TX_USECS,
307	.get_coalesce = emac_get_coalesce,
308	.set_coalesce = emac_set_coalesce,
309	.get_per_queue_coalesce = emac_get_per_queue_coalesce,
310	.set_per_queue_coalesce = emac_set_per_queue_coalesce,
311	.get_channels = emac_get_channels,
312	.set_channels = emac_set_channels,
313	.get_link_ksettings = emac_get_link_ksettings,
314	.set_link_ksettings = emac_set_link_ksettings,
315	.get_link = ethtool_op_get_link,
316	.get_eee = emac_get_eee,
317	.set_eee = emac_set_eee,
318	.nway_reset = emac_nway_reset,
319	.get_rmon_stats = emac_get_rmon_stats,
320};
321EXPORT_SYMBOL_GPL(icssg_ethtool_ops);