1 /*
2  * aQuantia Corporation Network Driver
3  * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU General Public License,
7  * version 2, as published by the Free Software Foundation.
8  */
9 
10 /* File aq_ethtool.c: Definition of ethertool related functions. */
11 
12 #include "aq_ethtool.h"
13 #include "aq_nic.h"
14 
15 static void aq_ethtool_get_regs(struct net_device *ndev,
16 				struct ethtool_regs *regs, void *p)
17 {
18 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
19 	u32 regs_count = aq_nic_get_regs_count(aq_nic);
20 
21 	memset(p, 0, regs_count * sizeof(u32));
22 	aq_nic_get_regs(aq_nic, regs, p);
23 }
24 
25 static int aq_ethtool_get_regs_len(struct net_device *ndev)
26 {
27 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
28 	u32 regs_count = aq_nic_get_regs_count(aq_nic);
29 
30 	return regs_count * sizeof(u32);
31 }
32 
33 static u32 aq_ethtool_get_link(struct net_device *ndev)
34 {
35 	return ethtool_op_get_link(ndev);
36 }
37 
38 static int aq_ethtool_get_link_ksettings(struct net_device *ndev,
39 					 struct ethtool_link_ksettings *cmd)
40 {
41 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
42 
43 	aq_nic_get_link_ksettings(aq_nic, cmd);
44 	cmd->base.speed = netif_carrier_ok(ndev) ?
45 				aq_nic_get_link_speed(aq_nic) : 0U;
46 
47 	return 0;
48 }
49 
50 static int
51 aq_ethtool_set_link_ksettings(struct net_device *ndev,
52 			      const struct ethtool_link_ksettings *cmd)
53 {
54 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
55 
56 	return aq_nic_set_link_ksettings(aq_nic, cmd);
57 }
58 
59 /* there "5U" is number of queue[#] stats lines (InPackets+...+InErrors) */
60 static const unsigned int aq_ethtool_stat_queue_lines = 5U;
61 static const unsigned int aq_ethtool_stat_queue_chars =
62 	5U * ETH_GSTRING_LEN;
63 static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
64 	"InPackets",
65 	"InUCast",
66 	"InMCast",
67 	"InBCast",
68 	"InErrors",
69 	"OutPackets",
70 	"OutUCast",
71 	"OutMCast",
72 	"OutBCast",
73 	"InUCastOctects",
74 	"OutUCastOctects",
75 	"InMCastOctects",
76 	"OutMCastOctects",
77 	"InBCastOctects",
78 	"OutBCastOctects",
79 	"InOctects",
80 	"OutOctects",
81 	"InPacketsDma",
82 	"OutPacketsDma",
83 	"InOctetsDma",
84 	"OutOctetsDma",
85 	"InDroppedDma",
86 	"Queue[0] InPackets",
87 	"Queue[0] OutPackets",
88 	"Queue[0] InJumboPackets",
89 	"Queue[0] InLroPackets",
90 	"Queue[0] InErrors",
91 	"Queue[1] InPackets",
92 	"Queue[1] OutPackets",
93 	"Queue[1] InJumboPackets",
94 	"Queue[1] InLroPackets",
95 	"Queue[1] InErrors",
96 	"Queue[2] InPackets",
97 	"Queue[2] OutPackets",
98 	"Queue[2] InJumboPackets",
99 	"Queue[2] InLroPackets",
100 	"Queue[2] InErrors",
101 	"Queue[3] InPackets",
102 	"Queue[3] OutPackets",
103 	"Queue[3] InJumboPackets",
104 	"Queue[3] InLroPackets",
105 	"Queue[3] InErrors",
106 	"Queue[4] InPackets",
107 	"Queue[4] OutPackets",
108 	"Queue[4] InJumboPackets",
109 	"Queue[4] InLroPackets",
110 	"Queue[4] InErrors",
111 	"Queue[5] InPackets",
112 	"Queue[5] OutPackets",
113 	"Queue[5] InJumboPackets",
114 	"Queue[5] InLroPackets",
115 	"Queue[5] InErrors",
116 	"Queue[6] InPackets",
117 	"Queue[6] OutPackets",
118 	"Queue[6] InJumboPackets",
119 	"Queue[6] InLroPackets",
120 	"Queue[6] InErrors",
121 	"Queue[7] InPackets",
122 	"Queue[7] OutPackets",
123 	"Queue[7] InJumboPackets",
124 	"Queue[7] InLroPackets",
125 	"Queue[7] InErrors",
126 };
127 
128 static void aq_ethtool_stats(struct net_device *ndev,
129 			     struct ethtool_stats *stats, u64 *data)
130 {
131 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
132 
133 /* ASSERT: Need add lines to aq_ethtool_stat_names if AQ_CFG_VECS_MAX > 8 */
134 	BUILD_BUG_ON(AQ_CFG_VECS_MAX > 8);
135 	memset(data, 0, ARRAY_SIZE(aq_ethtool_stat_names) * sizeof(u64));
136 	aq_nic_get_stats(aq_nic, data);
137 }
138 
139 static void aq_ethtool_get_drvinfo(struct net_device *ndev,
140 				   struct ethtool_drvinfo *drvinfo)
141 {
142 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
143 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
144 	struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
145 	u32 firmware_version = aq_nic_get_fw_version(aq_nic);
146 	u32 regs_count = aq_nic_get_regs_count(aq_nic);
147 
148 	strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver));
149 	strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version));
150 
151 	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
152 		 "%u.%u.%u", firmware_version >> 24,
153 		 (firmware_version >> 16) & 0xFFU, firmware_version & 0xFFFFU);
154 
155 	strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "",
156 		sizeof(drvinfo->bus_info));
157 	drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) -
158 		(AQ_CFG_VECS_MAX - cfg->vecs) * aq_ethtool_stat_queue_lines;
159 	drvinfo->testinfo_len = 0;
160 	drvinfo->regdump_len = regs_count;
161 	drvinfo->eedump_len = 0;
162 }
163 
164 static void aq_ethtool_get_strings(struct net_device *ndev,
165 				   u32 stringset, u8 *data)
166 {
167 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
168 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
169 
170 	if (stringset == ETH_SS_STATS)
171 		memcpy(data, *aq_ethtool_stat_names,
172 		       sizeof(aq_ethtool_stat_names) -
173 		       (AQ_CFG_VECS_MAX - cfg->vecs) *
174 		       aq_ethtool_stat_queue_chars);
175 }
176 
177 static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
178 {
179 	int ret = 0;
180 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
181 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
182 
183 	switch (stringset) {
184 	case ETH_SS_STATS:
185 		ret = ARRAY_SIZE(aq_ethtool_stat_names) -
186 			(AQ_CFG_VECS_MAX - cfg->vecs) *
187 			aq_ethtool_stat_queue_lines;
188 		break;
189 	default:
190 		ret = -EOPNOTSUPP;
191 	}
192 	return ret;
193 }
194 
195 static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev)
196 {
197 	return AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
198 }
199 
200 static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev)
201 {
202 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
203 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
204 
205 	return sizeof(cfg->aq_rss.hash_secret_key);
206 }
207 
208 static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
209 			      u8 *hfunc)
210 {
211 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
212 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
213 	unsigned int i = 0U;
214 
215 	if (hfunc)
216 		*hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
217 	if (indir) {
218 		for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++)
219 			indir[i] = cfg->aq_rss.indirection_table[i];
220 	}
221 	if (key)
222 		memcpy(key, cfg->aq_rss.hash_secret_key,
223 		       sizeof(cfg->aq_rss.hash_secret_key));
224 	return 0;
225 }
226 
227 static int aq_ethtool_get_rxnfc(struct net_device *ndev,
228 				struct ethtool_rxnfc *cmd,
229 				u32 *rule_locs)
230 {
231 	struct aq_nic_s *aq_nic = netdev_priv(ndev);
232 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
233 	int err = 0;
234 
235 	switch (cmd->cmd) {
236 	case ETHTOOL_GRXRINGS:
237 		cmd->data = cfg->vecs;
238 		break;
239 
240 	default:
241 		err = -EOPNOTSUPP;
242 		break;
243 	}
244 
245 	return err;
246 }
247 
248 const struct ethtool_ops aq_ethtool_ops = {
249 	.get_link            = aq_ethtool_get_link,
250 	.get_regs_len        = aq_ethtool_get_regs_len,
251 	.get_regs            = aq_ethtool_get_regs,
252 	.get_drvinfo         = aq_ethtool_get_drvinfo,
253 	.get_strings         = aq_ethtool_get_strings,
254 	.get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
255 	.get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
256 	.get_rxfh            = aq_ethtool_get_rss,
257 	.get_rxnfc           = aq_ethtool_get_rxnfc,
258 	.get_sset_count      = aq_ethtool_get_sset_count,
259 	.get_ethtool_stats   = aq_ethtool_stats,
260 	.get_link_ksettings  = aq_ethtool_get_link_ksettings,
261 	.set_link_ksettings  = aq_ethtool_set_link_ksettings,
262 };
263