aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/cisco
diff options
context:
space:
mode:
authorNeel Patel <neepatel@cisco.com>2013-07-22 12:59:18 -0400
committerDavid S. Miller <davem@davemloft.net>2013-07-24 20:01:55 -0400
commitf13bbc2f9aba00c7a37b499d23060616b9a4ef9e (patch)
treef4c4558aa86db49280116b4e376e8021f1a1535e /drivers/net/ethernet/cisco
parent59ea52dc461ebb05b78545064604d92faf8bb16f (diff)
drivers/net: enic: Move ethtool code to a separate file
This patch moves all enic ethtool hooks from enic_main.c to a new file enic_ethtool.c Signed-off-by: Neel Patel <neepatel@cisco.com> Signed-off-by: Christian Benvenuti <benve@cisco.com> Signed-off-by: Nishank Trivedi <nistrive@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/cisco')
-rw-r--r--drivers/net/ethernet/cisco/enic/Makefile3
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h48
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.h1
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c257
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c270
5 files changed, 309 insertions, 270 deletions
diff --git a/drivers/net/ethernet/cisco/enic/Makefile b/drivers/net/ethernet/cisco/enic/Makefile
index 9d4974bba247..e52296d9b256 100644
--- a/drivers/net/ethernet/cisco/enic/Makefile
+++ b/drivers/net/ethernet/cisco/enic/Makefile
@@ -1,5 +1,6 @@
1obj-$(CONFIG_ENIC) := enic.o 1obj-$(CONFIG_ENIC) := enic.o
2 2
3enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \ 3enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
4 enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o 4 enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o \
5 enic_ethtool.o
5 6
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index afe9b1662b8c..2e37c63981c1 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -127,9 +127,57 @@ static inline struct device *enic_get_dev(struct enic *enic)
127 return &(enic->pdev->dev); 127 return &(enic->pdev->dev);
128} 128}
129 129
130static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
131{
132 return rq;
133}
134
135static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
136{
137 return enic->rq_count + wq;
138}
139
140static inline unsigned int enic_legacy_io_intr(void)
141{
142 return 0;
143}
144
145static inline unsigned int enic_legacy_err_intr(void)
146{
147 return 1;
148}
149
150static inline unsigned int enic_legacy_notify_intr(void)
151{
152 return 2;
153}
154
155static inline unsigned int enic_msix_rq_intr(struct enic *enic,
156 unsigned int rq)
157{
158 return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
159}
160
161static inline unsigned int enic_msix_wq_intr(struct enic *enic,
162 unsigned int wq)
163{
164 return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
165}
166
167static inline unsigned int enic_msix_err_intr(struct enic *enic)
168{
169 return enic->rq_count + enic->wq_count;
170}
171
172static inline unsigned int enic_msix_notify_intr(struct enic *enic)
173{
174 return enic->rq_count + enic->wq_count + 1;
175}
176
130void enic_reset_addr_lists(struct enic *enic); 177void enic_reset_addr_lists(struct enic *enic);
131int enic_sriov_enabled(struct enic *enic); 178int enic_sriov_enabled(struct enic *enic);
132int enic_is_valid_vf(struct enic *enic, int vf); 179int enic_is_valid_vf(struct enic *enic, int vf);
133int enic_is_dynamic(struct enic *enic); 180int enic_is_dynamic(struct enic *enic);
181void enic_set_ethtool_ops(struct net_device *netdev);
134 182
135#endif /* _ENIC_H_ */ 183#endif /* _ENIC_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h
index 08bded051b93..129b14a4efb0 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.h
@@ -20,6 +20,7 @@
20#define _ENIC_DEV_H_ 20#define _ENIC_DEV_H_
21 21
22#include "vnic_dev.h" 22#include "vnic_dev.h"
23#include "vnic_vic.h"
23 24
24/* 25/*
25 * Calls the devcmd function given by argument vnicdevcmdfn. 26 * Calls the devcmd function given by argument vnicdevcmdfn.
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
new file mode 100644
index 000000000000..47e3562f4866
--- /dev/null
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -0,0 +1,257 @@
1/**
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{
256 SET_ETHTOOL_OPS(netdev, &enic_ethtool_ops);
257}
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 992ec2ee64d9..b12b32bc53a6 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -31,7 +31,6 @@
31#include <linux/if.h> 31#include <linux/if.h>
32#include <linux/if_ether.h> 32#include <linux/if_ether.h>
33#include <linux/if_vlan.h> 33#include <linux/if_vlan.h>
34#include <linux/ethtool.h>
35#include <linux/in.h> 34#include <linux/in.h>
36#include <linux/ip.h> 35#include <linux/ip.h>
37#include <linux/ipv6.h> 36#include <linux/ipv6.h>
@@ -73,57 +72,6 @@ MODULE_LICENSE("GPL");
73MODULE_VERSION(DRV_VERSION); 72MODULE_VERSION(DRV_VERSION);
74MODULE_DEVICE_TABLE(pci, enic_id_table); 73MODULE_DEVICE_TABLE(pci, enic_id_table);
75 74
76struct enic_stat {
77 char name[ETH_GSTRING_LEN];
78 unsigned int offset;
79};
80
81#define ENIC_TX_STAT(stat) \
82 { .name = #stat, .offset = offsetof(struct vnic_tx_stats, stat) / 8 }
83#define ENIC_RX_STAT(stat) \
84 { .name = #stat, .offset = offsetof(struct vnic_rx_stats, stat) / 8 }
85
86static const struct enic_stat enic_tx_stats[] = {
87 ENIC_TX_STAT(tx_frames_ok),
88 ENIC_TX_STAT(tx_unicast_frames_ok),
89 ENIC_TX_STAT(tx_multicast_frames_ok),
90 ENIC_TX_STAT(tx_broadcast_frames_ok),
91 ENIC_TX_STAT(tx_bytes_ok),
92 ENIC_TX_STAT(tx_unicast_bytes_ok),
93 ENIC_TX_STAT(tx_multicast_bytes_ok),
94 ENIC_TX_STAT(tx_broadcast_bytes_ok),
95 ENIC_TX_STAT(tx_drops),
96 ENIC_TX_STAT(tx_errors),
97 ENIC_TX_STAT(tx_tso),
98};
99
100static const struct enic_stat enic_rx_stats[] = {
101 ENIC_RX_STAT(rx_frames_ok),
102 ENIC_RX_STAT(rx_frames_total),
103 ENIC_RX_STAT(rx_unicast_frames_ok),
104 ENIC_RX_STAT(rx_multicast_frames_ok),
105 ENIC_RX_STAT(rx_broadcast_frames_ok),
106 ENIC_RX_STAT(rx_bytes_ok),
107 ENIC_RX_STAT(rx_unicast_bytes_ok),
108 ENIC_RX_STAT(rx_multicast_bytes_ok),
109 ENIC_RX_STAT(rx_broadcast_bytes_ok),
110 ENIC_RX_STAT(rx_drop),
111 ENIC_RX_STAT(rx_no_bufs),
112 ENIC_RX_STAT(rx_errors),
113 ENIC_RX_STAT(rx_rss),
114 ENIC_RX_STAT(rx_crc_errors),
115 ENIC_RX_STAT(rx_frames_64),
116 ENIC_RX_STAT(rx_frames_127),
117 ENIC_RX_STAT(rx_frames_255),
118 ENIC_RX_STAT(rx_frames_511),
119 ENIC_RX_STAT(rx_frames_1023),
120 ENIC_RX_STAT(rx_frames_1518),
121 ENIC_RX_STAT(rx_frames_to_max),
122};
123
124static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
125static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
126
127int enic_is_dynamic(struct enic *enic) 75int enic_is_dynamic(struct enic *enic)
128{ 76{
129 return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN; 77 return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
@@ -148,222 +96,6 @@ int enic_is_valid_vf(struct enic *enic, int vf)
148#endif 96#endif
149} 97}
150 98
151static inline unsigned int enic_cq_rq(struct enic *enic, unsigned int rq)
152{
153 return rq;
154}
155
156static inline unsigned int enic_cq_wq(struct enic *enic, unsigned int wq)
157{
158 return enic->rq_count + wq;
159}
160
161static inline unsigned int enic_legacy_io_intr(void)
162{
163 return 0;
164}
165
166static inline unsigned int enic_legacy_err_intr(void)
167{
168 return 1;
169}
170
171static inline unsigned int enic_legacy_notify_intr(void)
172{
173 return 2;
174}
175
176static inline unsigned int enic_msix_rq_intr(struct enic *enic, unsigned int rq)
177{
178 return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;
179}
180
181static inline unsigned int enic_msix_wq_intr(struct enic *enic, unsigned int wq)
182{
183 return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;
184}
185
186static inline unsigned int enic_msix_err_intr(struct enic *enic)
187{
188 return enic->rq_count + enic->wq_count;
189}
190
191static inline unsigned int enic_msix_notify_intr(struct enic *enic)
192{
193 return enic->rq_count + enic->wq_count + 1;
194}
195
196static int enic_get_settings(struct net_device *netdev,
197 struct ethtool_cmd *ecmd)
198{
199 struct enic *enic = netdev_priv(netdev);
200
201 ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
202 ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
203 ecmd->port = PORT_FIBRE;
204 ecmd->transceiver = XCVR_EXTERNAL;
205
206 if (netif_carrier_ok(netdev)) {
207 ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
208 ecmd->duplex = DUPLEX_FULL;
209 } else {
210 ethtool_cmd_speed_set(ecmd, -1);
211 ecmd->duplex = -1;
212 }
213
214 ecmd->autoneg = AUTONEG_DISABLE;
215
216 return 0;
217}
218
219static void enic_get_drvinfo(struct net_device *netdev,
220 struct ethtool_drvinfo *drvinfo)
221{
222 struct enic *enic = netdev_priv(netdev);
223 struct vnic_devcmd_fw_info *fw_info;
224
225 enic_dev_fw_info(enic, &fw_info);
226
227 strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
228 strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
229 strlcpy(drvinfo->fw_version, fw_info->fw_version,
230 sizeof(drvinfo->fw_version));
231 strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
232 sizeof(drvinfo->bus_info));
233}
234
235static void enic_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
236{
237 unsigned int i;
238
239 switch (stringset) {
240 case ETH_SS_STATS:
241 for (i = 0; i < enic_n_tx_stats; i++) {
242 memcpy(data, enic_tx_stats[i].name, ETH_GSTRING_LEN);
243 data += ETH_GSTRING_LEN;
244 }
245 for (i = 0; i < enic_n_rx_stats; i++) {
246 memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
247 data += ETH_GSTRING_LEN;
248 }
249 break;
250 }
251}
252
253static int enic_get_sset_count(struct net_device *netdev, int sset)
254{
255 switch (sset) {
256 case ETH_SS_STATS:
257 return enic_n_tx_stats + enic_n_rx_stats;
258 default:
259 return -EOPNOTSUPP;
260 }
261}
262
263static void enic_get_ethtool_stats(struct net_device *netdev,
264 struct ethtool_stats *stats, u64 *data)
265{
266 struct enic *enic = netdev_priv(netdev);
267 struct vnic_stats *vstats;
268 unsigned int i;
269
270 enic_dev_stats_dump(enic, &vstats);
271
272 for (i = 0; i < enic_n_tx_stats; i++)
273 *(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].offset];
274 for (i = 0; i < enic_n_rx_stats; i++)
275 *(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset];
276}
277
278static u32 enic_get_msglevel(struct net_device *netdev)
279{
280 struct enic *enic = netdev_priv(netdev);
281 return enic->msg_enable;
282}
283
284static void enic_set_msglevel(struct net_device *netdev, u32 value)
285{
286 struct enic *enic = netdev_priv(netdev);
287 enic->msg_enable = value;
288}
289
290static int enic_get_coalesce(struct net_device *netdev,
291 struct ethtool_coalesce *ecmd)
292{
293 struct enic *enic = netdev_priv(netdev);
294
295 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
296 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
297
298 return 0;
299}
300
301static int enic_set_coalesce(struct net_device *netdev,
302 struct ethtool_coalesce *ecmd)
303{
304 struct enic *enic = netdev_priv(netdev);
305 u32 tx_coalesce_usecs;
306 u32 rx_coalesce_usecs;
307 unsigned int i, intr;
308
309 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
310 vnic_dev_get_intr_coal_timer_max(enic->vdev));
311 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
312 vnic_dev_get_intr_coal_timer_max(enic->vdev));
313
314 switch (vnic_dev_get_intr_mode(enic->vdev)) {
315 case VNIC_DEV_INTR_MODE_INTX:
316 if (tx_coalesce_usecs != rx_coalesce_usecs)
317 return -EINVAL;
318
319 intr = enic_legacy_io_intr();
320 vnic_intr_coalescing_timer_set(&enic->intr[intr],
321 tx_coalesce_usecs);
322 break;
323 case VNIC_DEV_INTR_MODE_MSI:
324 if (tx_coalesce_usecs != rx_coalesce_usecs)
325 return -EINVAL;
326
327 vnic_intr_coalescing_timer_set(&enic->intr[0],
328 tx_coalesce_usecs);
329 break;
330 case VNIC_DEV_INTR_MODE_MSIX:
331 for (i = 0; i < enic->wq_count; i++) {
332 intr = enic_msix_wq_intr(enic, i);
333 vnic_intr_coalescing_timer_set(&enic->intr[intr],
334 tx_coalesce_usecs);
335 }
336
337 for (i = 0; i < enic->rq_count; i++) {
338 intr = enic_msix_rq_intr(enic, i);
339 vnic_intr_coalescing_timer_set(&enic->intr[intr],
340 rx_coalesce_usecs);
341 }
342
343 break;
344 default:
345 break;
346 }
347
348 enic->tx_coalesce_usecs = tx_coalesce_usecs;
349 enic->rx_coalesce_usecs = rx_coalesce_usecs;
350
351 return 0;
352}
353
354static const struct ethtool_ops enic_ethtool_ops = {
355 .get_settings = enic_get_settings,
356 .get_drvinfo = enic_get_drvinfo,
357 .get_msglevel = enic_get_msglevel,
358 .set_msglevel = enic_set_msglevel,
359 .get_link = ethtool_op_get_link,
360 .get_strings = enic_get_strings,
361 .get_sset_count = enic_get_sset_count,
362 .get_ethtool_stats = enic_get_ethtool_stats,
363 .get_coalesce = enic_get_coalesce,
364 .set_coalesce = enic_set_coalesce,
365};
366
367static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) 99static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
368{ 100{
369 struct enic *enic = vnic_dev_priv(wq->vdev); 101 struct enic *enic = vnic_dev_priv(wq->vdev);
@@ -2496,7 +2228,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2496 netdev->netdev_ops = &enic_netdev_ops; 2228 netdev->netdev_ops = &enic_netdev_ops;
2497 2229
2498 netdev->watchdog_timeo = 2 * HZ; 2230 netdev->watchdog_timeo = 2 * HZ;
2499 netdev->ethtool_ops = &enic_ethtool_ops; 2231 enic_set_ethtool_ops(netdev);
2500 2232
2501 netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 2233 netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
2502 if (ENIC_SETTING(enic, LOOP)) { 2234 if (ENIC_SETTING(enic, LOOP)) {