blob: 58a8c67638e349673c53844725197fcd1b1e24da [file] [log] [blame]
Neel Patelf13bbc22013-07-22 09:59:18 -07001/**
2 * Copyright 2013 Cisco Systems, Inc. All rights reserved.
3 *
4 * This program is free software; you may redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15 * SOFTWARE.
16 *
17 */
18
19#include <linux/netdevice.h>
20#include <linux/ethtool.h>
21
22#include "enic_res.h"
23#include "enic.h"
24#include "enic_dev.h"
25
26struct enic_stat {
27 char name[ETH_GSTRING_LEN];
28 unsigned int index;
29};
30
31#define ENIC_TX_STAT(stat) { \
32 .name = #stat, \
33 .index = offsetof(struct vnic_tx_stats, stat) / sizeof(u64) \
34}
35
36#define ENIC_RX_STAT(stat) { \
37 .name = #stat, \
38 .index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \
39}
40
41static const struct enic_stat enic_tx_stats[] = {
42 ENIC_TX_STAT(tx_frames_ok),
43 ENIC_TX_STAT(tx_unicast_frames_ok),
44 ENIC_TX_STAT(tx_multicast_frames_ok),
45 ENIC_TX_STAT(tx_broadcast_frames_ok),
46 ENIC_TX_STAT(tx_bytes_ok),
47 ENIC_TX_STAT(tx_unicast_bytes_ok),
48 ENIC_TX_STAT(tx_multicast_bytes_ok),
49 ENIC_TX_STAT(tx_broadcast_bytes_ok),
50 ENIC_TX_STAT(tx_drops),
51 ENIC_TX_STAT(tx_errors),
52 ENIC_TX_STAT(tx_tso),
53};
54
55static const struct enic_stat enic_rx_stats[] = {
56 ENIC_RX_STAT(rx_frames_ok),
57 ENIC_RX_STAT(rx_frames_total),
58 ENIC_RX_STAT(rx_unicast_frames_ok),
59 ENIC_RX_STAT(rx_multicast_frames_ok),
60 ENIC_RX_STAT(rx_broadcast_frames_ok),
61 ENIC_RX_STAT(rx_bytes_ok),
62 ENIC_RX_STAT(rx_unicast_bytes_ok),
63 ENIC_RX_STAT(rx_multicast_bytes_ok),
64 ENIC_RX_STAT(rx_broadcast_bytes_ok),
65 ENIC_RX_STAT(rx_drop),
66 ENIC_RX_STAT(rx_no_bufs),
67 ENIC_RX_STAT(rx_errors),
68 ENIC_RX_STAT(rx_rss),
69 ENIC_RX_STAT(rx_crc_errors),
70 ENIC_RX_STAT(rx_frames_64),
71 ENIC_RX_STAT(rx_frames_127),
72 ENIC_RX_STAT(rx_frames_255),
73 ENIC_RX_STAT(rx_frames_511),
74 ENIC_RX_STAT(rx_frames_1023),
75 ENIC_RX_STAT(rx_frames_1518),
76 ENIC_RX_STAT(rx_frames_to_max),
77};
78
79static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
80static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
81
82static int enic_get_settings(struct net_device *netdev,
83 struct ethtool_cmd *ecmd)
84{
85 struct enic *enic = netdev_priv(netdev);
86
87 ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
88 ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
89 ecmd->port = PORT_FIBRE;
90 ecmd->transceiver = XCVR_EXTERNAL;
91
92 if (netif_carrier_ok(netdev)) {
93 ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
94 ecmd->duplex = DUPLEX_FULL;
95 } else {
96 ethtool_cmd_speed_set(ecmd, -1);
97 ecmd->duplex = -1;
98 }
99
100 ecmd->autoneg = AUTONEG_DISABLE;
101
102 return 0;
103}
104
105static void enic_get_drvinfo(struct net_device *netdev,
106 struct ethtool_drvinfo *drvinfo)
107{
108 struct enic *enic = netdev_priv(netdev);
109 struct vnic_devcmd_fw_info *fw_info;
110
111 enic_dev_fw_info(enic, &fw_info);
112
113 strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
114 strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
115 strlcpy(drvinfo->fw_version, fw_info->fw_version,
116 sizeof(drvinfo->fw_version));
117 strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
118 sizeof(drvinfo->bus_info));
119}
120
121static void enic_get_strings(struct net_device *netdev, u32 stringset,
122 u8 *data)
123{
124 unsigned int i;
125
126 switch (stringset) {
127 case ETH_SS_STATS:
128 for (i = 0; i < enic_n_tx_stats; i++) {
129 memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
130 data += ETH_GSTRING_LEN;
131 }
132 for (i = 0; i < enic_n_rx_stats; i++) {
133 memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
134 data += ETH_GSTRING_LEN;
135 }
136 break;
137 }
138}
139
140static int enic_get_sset_count(struct net_device *netdev, int sset)
141{
142 switch (sset) {
143 case ETH_SS_STATS:
144 return enic_n_tx_stats + enic_n_rx_stats;
145 default:
146 return -EOPNOTSUPP;
147 }
148}
149
150static void enic_get_ethtool_stats(struct net_device *netdev,
151 struct ethtool_stats *stats, u64 *data)
152{
153 struct enic *enic = netdev_priv(netdev);
154 struct vnic_stats *vstats;
155 unsigned int i;
156
157 enic_dev_stats_dump(enic, &vstats);
158
159 for (i = 0; i < enic_n_tx_stats; i++)
160 *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];
161 for (i = 0; i < enic_n_rx_stats; i++)
162 *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index];
163}
164
165static u32 enic_get_msglevel(struct net_device *netdev)
166{
167 struct enic *enic = netdev_priv(netdev);
168 return enic->msg_enable;
169}
170
171static void enic_set_msglevel(struct net_device *netdev, u32 value)
172{
173 struct enic *enic = netdev_priv(netdev);
174 enic->msg_enable = value;
175}
176
177static int enic_get_coalesce(struct net_device *netdev,
178 struct ethtool_coalesce *ecmd)
179{
180 struct enic *enic = netdev_priv(netdev);
181
182 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
183 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
184
185 return 0;
186}
187
188static int enic_set_coalesce(struct net_device *netdev,
189 struct ethtool_coalesce *ecmd)
190{
191 struct enic *enic = netdev_priv(netdev);
192 u32 tx_coalesce_usecs;
193 u32 rx_coalesce_usecs;
194 unsigned int i, intr;
195
196 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
197 vnic_dev_get_intr_coal_timer_max(enic->vdev));
198 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
199 vnic_dev_get_intr_coal_timer_max(enic->vdev));
200
201 switch (vnic_dev_get_intr_mode(enic->vdev)) {
202 case VNIC_DEV_INTR_MODE_INTX:
203 if (tx_coalesce_usecs != rx_coalesce_usecs)
204 return -EINVAL;
205
206 intr = enic_legacy_io_intr();
207 vnic_intr_coalescing_timer_set(&enic->intr[intr],
208 tx_coalesce_usecs);
209 break;
210 case VNIC_DEV_INTR_MODE_MSI:
211 if (tx_coalesce_usecs != rx_coalesce_usecs)
212 return -EINVAL;
213
214 vnic_intr_coalescing_timer_set(&enic->intr[0],
215 tx_coalesce_usecs);
216 break;
217 case VNIC_DEV_INTR_MODE_MSIX:
218 for (i = 0; i < enic->wq_count; i++) {
219 intr = enic_msix_wq_intr(enic, i);
220 vnic_intr_coalescing_timer_set(&enic->intr[intr],
221 tx_coalesce_usecs);
222 }
223
224 for (i = 0; i < enic->rq_count; i++) {
225 intr = enic_msix_rq_intr(enic, i);
226 vnic_intr_coalescing_timer_set(&enic->intr[intr],
227 rx_coalesce_usecs);
228 }
229
230 break;
231 default:
232 break;
233 }
234
235 enic->tx_coalesce_usecs = tx_coalesce_usecs;
236 enic->rx_coalesce_usecs = rx_coalesce_usecs;
237
238 return 0;
239}
240
241static const struct ethtool_ops enic_ethtool_ops = {
242 .get_settings = enic_get_settings,
243 .get_drvinfo = enic_get_drvinfo,
244 .get_msglevel = enic_get_msglevel,
245 .set_msglevel = enic_set_msglevel,
246 .get_link = ethtool_op_get_link,
247 .get_strings = enic_get_strings,
248 .get_sset_count = enic_get_sset_count,
249 .get_ethtool_stats = enic_get_ethtool_stats,
250 .get_coalesce = enic_get_coalesce,
251 .set_coalesce = enic_set_coalesce,
252};
253
254void enic_set_ethtool_ops(struct net_device *netdev)
255{
Wilfried Klaebe7ad24ea2014-05-11 00:12:32 +0000256 netdev->ethtool_ops = &enic_ethtool_ops;
Neel Patelf13bbc22013-07-22 09:59:18 -0700257}