GNU Linux-libre 4.19.281-gnu1
[releases.git] / drivers / net / ethernet / aquantia / atlantic / aq_ethtool.c
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 #include "aq_vec.h"
15
16 static void aq_ethtool_get_regs(struct net_device *ndev,
17                                 struct ethtool_regs *regs, void *p)
18 {
19         struct aq_nic_s *aq_nic = netdev_priv(ndev);
20         u32 regs_count = aq_nic_get_regs_count(aq_nic);
21
22         memset(p, 0, regs_count * sizeof(u32));
23         aq_nic_get_regs(aq_nic, regs, p);
24 }
25
26 static int aq_ethtool_get_regs_len(struct net_device *ndev)
27 {
28         struct aq_nic_s *aq_nic = netdev_priv(ndev);
29         u32 regs_count = aq_nic_get_regs_count(aq_nic);
30
31         return regs_count * sizeof(u32);
32 }
33
34 static u32 aq_ethtool_get_link(struct net_device *ndev)
35 {
36         return ethtool_op_get_link(ndev);
37 }
38
39 static int aq_ethtool_get_link_ksettings(struct net_device *ndev,
40                                          struct ethtool_link_ksettings *cmd)
41 {
42         struct aq_nic_s *aq_nic = netdev_priv(ndev);
43
44         aq_nic_get_link_ksettings(aq_nic, cmd);
45         cmd->base.speed = netif_carrier_ok(ndev) ?
46                                 aq_nic_get_link_speed(aq_nic) : 0U;
47
48         return 0;
49 }
50
51 static int
52 aq_ethtool_set_link_ksettings(struct net_device *ndev,
53                               const struct ethtool_link_ksettings *cmd)
54 {
55         struct aq_nic_s *aq_nic = netdev_priv(ndev);
56
57         return aq_nic_set_link_ksettings(aq_nic, cmd);
58 }
59
60 static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = {
61         "InPackets",
62         "InUCast",
63         "InMCast",
64         "InBCast",
65         "InErrors",
66         "OutPackets",
67         "OutUCast",
68         "OutMCast",
69         "OutBCast",
70         "InUCastOctets",
71         "OutUCastOctets",
72         "InMCastOctets",
73         "OutMCastOctets",
74         "InBCastOctets",
75         "OutBCastOctets",
76         "InOctets",
77         "OutOctets",
78         "InPacketsDma",
79         "OutPacketsDma",
80         "InOctetsDma",
81         "OutOctetsDma",
82         "InDroppedDma",
83 };
84
85 static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = {
86         "Queue[%d] InPackets",
87         "Queue[%d] OutPackets",
88         "Queue[%d] Restarts",
89         "Queue[%d] InJumboPackets",
90         "Queue[%d] InLroPackets",
91         "Queue[%d] InErrors",
92 };
93
94 static void aq_ethtool_stats(struct net_device *ndev,
95                              struct ethtool_stats *stats, u64 *data)
96 {
97         struct aq_nic_s *aq_nic = netdev_priv(ndev);
98         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
99
100         memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) +
101                                 ARRAY_SIZE(aq_ethtool_queue_stat_names) *
102                                 cfg->vecs) * sizeof(u64));
103         aq_nic_get_stats(aq_nic, data);
104 }
105
106 static void aq_ethtool_get_drvinfo(struct net_device *ndev,
107                                    struct ethtool_drvinfo *drvinfo)
108 {
109         struct aq_nic_s *aq_nic = netdev_priv(ndev);
110         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
111         struct pci_dev *pdev = to_pci_dev(ndev->dev.parent);
112         u32 firmware_version = aq_nic_get_fw_version(aq_nic);
113         u32 regs_count = aq_nic_get_regs_count(aq_nic);
114
115         strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver));
116         strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version));
117
118         snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
119                  "%u.%u.%u", firmware_version >> 24,
120                  (firmware_version >> 16) & 0xFFU, firmware_version & 0xFFFFU);
121
122         strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "",
123                 sizeof(drvinfo->bus_info));
124         drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) +
125                 cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
126         drvinfo->testinfo_len = 0;
127         drvinfo->regdump_len = regs_count;
128         drvinfo->eedump_len = 0;
129 }
130
131 static void aq_ethtool_get_strings(struct net_device *ndev,
132                                    u32 stringset, u8 *data)
133 {
134         int i, si;
135         struct aq_nic_s *aq_nic = netdev_priv(ndev);
136         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
137         u8 *p = data;
138
139         if (stringset == ETH_SS_STATS) {
140                 memcpy(p, *aq_ethtool_stat_names,
141                        sizeof(aq_ethtool_stat_names));
142                 p = p + sizeof(aq_ethtool_stat_names);
143                 for (i = 0; i < cfg->vecs; i++) {
144                         for (si = 0;
145                                 si < ARRAY_SIZE(aq_ethtool_queue_stat_names);
146                                 si++) {
147                                 snprintf(p, ETH_GSTRING_LEN,
148                                          aq_ethtool_queue_stat_names[si], i);
149                                 p += ETH_GSTRING_LEN;
150                         }
151                 }
152         }
153 }
154
155 static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset)
156 {
157         int ret = 0;
158         struct aq_nic_s *aq_nic = netdev_priv(ndev);
159         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
160
161         switch (stringset) {
162         case ETH_SS_STATS:
163                 ret = ARRAY_SIZE(aq_ethtool_stat_names) +
164                         cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names);
165                 break;
166         default:
167                 ret = -EOPNOTSUPP;
168         }
169         return ret;
170 }
171
172 static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev)
173 {
174         return AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
175 }
176
177 static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev)
178 {
179         struct aq_nic_s *aq_nic = netdev_priv(ndev);
180         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
181
182         return sizeof(cfg->aq_rss.hash_secret_key);
183 }
184
185 static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key,
186                               u8 *hfunc)
187 {
188         struct aq_nic_s *aq_nic = netdev_priv(ndev);
189         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
190         unsigned int i = 0U;
191
192         if (hfunc)
193                 *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
194         if (indir) {
195                 for (i = 0; i < AQ_CFG_RSS_INDIRECTION_TABLE_MAX; i++)
196                         indir[i] = cfg->aq_rss.indirection_table[i];
197         }
198         if (key)
199                 memcpy(key, cfg->aq_rss.hash_secret_key,
200                        sizeof(cfg->aq_rss.hash_secret_key));
201         return 0;
202 }
203
204 static int aq_ethtool_get_rxnfc(struct net_device *ndev,
205                                 struct ethtool_rxnfc *cmd,
206                                 u32 *rule_locs)
207 {
208         struct aq_nic_s *aq_nic = netdev_priv(ndev);
209         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
210         int err = 0;
211
212         switch (cmd->cmd) {
213         case ETHTOOL_GRXRINGS:
214                 cmd->data = cfg->vecs;
215                 break;
216
217         default:
218                 err = -EOPNOTSUPP;
219                 break;
220         }
221
222         return err;
223 }
224
225 static int aq_ethtool_get_coalesce(struct net_device *ndev,
226                                    struct ethtool_coalesce *coal)
227 {
228         struct aq_nic_s *aq_nic = netdev_priv(ndev);
229         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
230
231         if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON ||
232             cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) {
233                 coal->rx_coalesce_usecs = cfg->rx_itr;
234                 coal->tx_coalesce_usecs = cfg->tx_itr;
235                 coal->rx_max_coalesced_frames = 0;
236                 coal->tx_max_coalesced_frames = 0;
237         } else {
238                 coal->rx_coalesce_usecs = 0;
239                 coal->tx_coalesce_usecs = 0;
240                 coal->rx_max_coalesced_frames = 1;
241                 coal->tx_max_coalesced_frames = 1;
242         }
243         return 0;
244 }
245
246 static int aq_ethtool_set_coalesce(struct net_device *ndev,
247                                    struct ethtool_coalesce *coal)
248 {
249         struct aq_nic_s *aq_nic = netdev_priv(ndev);
250         struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic);
251
252         /* This is not yet supported
253          */
254         if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce)
255                 return -EOPNOTSUPP;
256
257         /* Atlantic only supports timing based coalescing
258          */
259         if (coal->rx_max_coalesced_frames > 1 ||
260             coal->rx_coalesce_usecs_irq ||
261             coal->rx_max_coalesced_frames_irq)
262                 return -EOPNOTSUPP;
263
264         if (coal->tx_max_coalesced_frames > 1 ||
265             coal->tx_coalesce_usecs_irq ||
266             coal->tx_max_coalesced_frames_irq)
267                 return -EOPNOTSUPP;
268
269         /* We do not support frame counting. Check this
270          */
271         if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs))
272                 return -EOPNOTSUPP;
273         if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs))
274                 return -EOPNOTSUPP;
275
276         if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX ||
277             coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX)
278                 return -EINVAL;
279
280         cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON;
281
282         cfg->rx_itr = coal->rx_coalesce_usecs;
283         cfg->tx_itr = coal->tx_coalesce_usecs;
284
285         return aq_nic_update_interrupt_moderation_settings(aq_nic);
286 }
287
288 static int aq_ethtool_nway_reset(struct net_device *ndev)
289 {
290         struct aq_nic_s *aq_nic = netdev_priv(ndev);
291
292         if (unlikely(!aq_nic->aq_fw_ops->renegotiate))
293                 return -EOPNOTSUPP;
294
295         if (netif_running(ndev))
296                 return aq_nic->aq_fw_ops->renegotiate(aq_nic->aq_hw);
297
298         return 0;
299 }
300
301 static void aq_ethtool_get_pauseparam(struct net_device *ndev,
302                                       struct ethtool_pauseparam *pause)
303 {
304         struct aq_nic_s *aq_nic = netdev_priv(ndev);
305
306         pause->autoneg = 0;
307
308         if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX)
309                 pause->rx_pause = 1;
310         if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX)
311                 pause->tx_pause = 1;
312 }
313
314 static int aq_ethtool_set_pauseparam(struct net_device *ndev,
315                                      struct ethtool_pauseparam *pause)
316 {
317         struct aq_nic_s *aq_nic = netdev_priv(ndev);
318         int err = 0;
319
320         if (!aq_nic->aq_fw_ops->set_flow_control)
321                 return -EOPNOTSUPP;
322
323         if (pause->autoneg == AUTONEG_ENABLE)
324                 return -EOPNOTSUPP;
325
326         if (pause->rx_pause)
327                 aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX;
328         else
329                 aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX;
330
331         if (pause->tx_pause)
332                 aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX;
333         else
334                 aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX;
335
336         err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw);
337
338         return err;
339 }
340
341 static void aq_get_ringparam(struct net_device *ndev,
342                              struct ethtool_ringparam *ring)
343 {
344         struct aq_nic_s *aq_nic = netdev_priv(ndev);
345         struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
346
347         ring->rx_pending = aq_nic_cfg->rxds;
348         ring->tx_pending = aq_nic_cfg->txds;
349
350         ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max;
351         ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max;
352 }
353
354 static int aq_set_ringparam(struct net_device *ndev,
355                             struct ethtool_ringparam *ring)
356 {
357         int err = 0;
358         bool ndev_running = false;
359         struct aq_nic_s *aq_nic = netdev_priv(ndev);
360         struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic);
361         const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps;
362
363         if (ring->rx_mini_pending || ring->rx_jumbo_pending) {
364                 err = -EOPNOTSUPP;
365                 goto err_exit;
366         }
367
368         if (netif_running(ndev)) {
369                 ndev_running = true;
370                 dev_close(ndev);
371         }
372
373         aq_nic_free_vectors(aq_nic);
374
375         aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min);
376         aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max);
377         aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE);
378
379         aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min);
380         aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max);
381         aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE);
382
383         for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs;
384              aq_nic->aq_vecs++) {
385                 aq_nic->aq_vec[aq_nic->aq_vecs] =
386                     aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg);
387                 if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) {
388                         err = -ENOMEM;
389                         goto err_exit;
390                 }
391         }
392         if (ndev_running)
393                 err = dev_open(ndev);
394
395 err_exit:
396         return err;
397 }
398
399 const struct ethtool_ops aq_ethtool_ops = {
400         .get_link            = aq_ethtool_get_link,
401         .get_regs_len        = aq_ethtool_get_regs_len,
402         .get_regs            = aq_ethtool_get_regs,
403         .get_drvinfo         = aq_ethtool_get_drvinfo,
404         .get_strings         = aq_ethtool_get_strings,
405         .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size,
406         .nway_reset          = aq_ethtool_nway_reset,
407         .get_ringparam       = aq_get_ringparam,
408         .set_ringparam       = aq_set_ringparam,
409         .get_pauseparam      = aq_ethtool_get_pauseparam,
410         .set_pauseparam      = aq_ethtool_set_pauseparam,
411         .get_rxfh_key_size   = aq_ethtool_get_rss_key_size,
412         .get_rxfh            = aq_ethtool_get_rss,
413         .get_rxnfc           = aq_ethtool_get_rxnfc,
414         .get_sset_count      = aq_ethtool_get_sset_count,
415         .get_ethtool_stats   = aq_ethtool_stats,
416         .get_link_ksettings  = aq_ethtool_get_link_ksettings,
417         .set_link_ksettings  = aq_ethtool_set_link_ksettings,
418         .get_coalesce        = aq_ethtool_get_coalesce,
419         .set_coalesce        = aq_ethtool_set_coalesce,
420 };