aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/enic
diff options
context:
space:
mode:
authorScott Feldman <scofeldm@cisco.com>2009-12-23 08:27:54 -0500
committerDavid S. Miller <davem@davemloft.net>2009-12-24 00:03:41 -0500
commit7c8445991172cc17eaca9f7de0a300c02caaa49d (patch)
tree0518a514d0d3e5af0d6442a2ef72aa10bbce58ae /drivers/net/enic
parentbd2496229e702b2eb50eab5589858a3cdb7847b2 (diff)
enic: feature add: add ethtool -c/C support
Only rx_usec and tx_usec options for ethtool -C are settable as those are the only settings that make sense to HW. Adds driver reporting of intr coalescing timer value in usec units rather than HW units. Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com> Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic')
-rw-r--r--drivers/net/enic/enic.h2
-rw-r--r--drivers/net/enic/enic_main.c63
-rw-r--r--drivers/net/enic/enic_res.c12
-rw-r--r--drivers/net/enic/vnic_enet.h5
-rw-r--r--drivers/net/enic/vnic_intr.c8
-rw-r--r--drivers/net/enic/vnic_intr.h2
6 files changed, 85 insertions, 7 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index b090d65ad0c8..ee01f5a6d0d4 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -93,6 +93,8 @@ struct enic {
93 unsigned int mc_count; 93 unsigned int mc_count;
94 int csum_rx_enabled; 94 int csum_rx_enabled;
95 u32 port_mtu; 95 u32 port_mtu;
96 u32 rx_coalesce_usecs;
97 u32 tx_coalesce_usecs;
96 98
97 /* work queue cache line section */ 99 /* work queue cache line section */
98 ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; 100 ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 019b1480cc0c..e56f41672b37 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
261 enic->msg_enable = value; 261 enic->msg_enable = value;
262} 262}
263 263
264static int enic_get_coalesce(struct net_device *netdev,
265 struct ethtool_coalesce *ecmd)
266{
267 struct enic *enic = netdev_priv(netdev);
268
269 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
270 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
271
272 return 0;
273}
274
275static int enic_set_coalesce(struct net_device *netdev,
276 struct ethtool_coalesce *ecmd)
277{
278 struct enic *enic = netdev_priv(netdev);
279 u32 tx_coalesce_usecs;
280 u32 rx_coalesce_usecs;
281
282 tx_coalesce_usecs = min_t(u32,
283 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
284 ecmd->tx_coalesce_usecs);
285 rx_coalesce_usecs = min_t(u32,
286 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
287 ecmd->rx_coalesce_usecs);
288
289 switch (vnic_dev_get_intr_mode(enic->vdev)) {
290 case VNIC_DEV_INTR_MODE_INTX:
291 if (tx_coalesce_usecs != rx_coalesce_usecs)
292 return -EINVAL;
293
294 vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
295 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
296 break;
297 case VNIC_DEV_INTR_MODE_MSI:
298 if (tx_coalesce_usecs != rx_coalesce_usecs)
299 return -EINVAL;
300
301 vnic_intr_coalescing_timer_set(&enic->intr[0],
302 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
303 break;
304 case VNIC_DEV_INTR_MODE_MSIX:
305 vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
306 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
307 vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
308 INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
309 break;
310 default:
311 break;
312 }
313
314 enic->tx_coalesce_usecs = tx_coalesce_usecs;
315 enic->rx_coalesce_usecs = rx_coalesce_usecs;
316
317 return 0;
318}
319
264static const struct ethtool_ops enic_ethtool_ops = { 320static const struct ethtool_ops enic_ethtool_ops = {
265 .get_settings = enic_get_settings, 321 .get_settings = enic_get_settings,
266 .get_drvinfo = enic_get_drvinfo, 322 .get_drvinfo = enic_get_drvinfo,
@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
278 .set_sg = ethtool_op_set_sg, 334 .set_sg = ethtool_op_set_sg,
279 .get_tso = ethtool_op_get_tso, 335 .get_tso = ethtool_op_get_tso,
280 .set_tso = enic_set_tso, 336 .set_tso = enic_set_tso,
337 .get_coalesce = enic_get_coalesce,
338 .set_coalesce = enic_set_coalesce,
281 .get_flags = ethtool_op_get_flags, 339 .get_flags = ethtool_op_get_flags,
282 .set_flags = ethtool_op_set_flags, 340 .set_flags = ethtool_op_set_flags,
283}; 341};
@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
363 u32 mtu = vnic_dev_mtu(enic->vdev); 421 u32 mtu = vnic_dev_mtu(enic->vdev);
364 422
365 if (mtu && mtu != enic->port_mtu) { 423 if (mtu && mtu != enic->port_mtu) {
424 enic->port_mtu = mtu;
366 if (mtu < enic->netdev->mtu) 425 if (mtu < enic->netdev->mtu)
367 printk(KERN_WARNING PFX 426 printk(KERN_WARNING PFX
368 "%s: interface MTU (%d) set higher " 427 "%s: interface MTU (%d) set higher "
369 "than switch port MTU (%d)\n", 428 "than switch port MTU (%d)\n",
370 enic->netdev->name, enic->netdev->mtu, mtu); 429 enic->netdev->name, enic->netdev->mtu, mtu);
371 enic->port_mtu = mtu;
372 } 430 }
373} 431}
374 432
@@ -1990,6 +2048,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
1990 goto err_out_dev_deinit; 2048 goto err_out_dev_deinit;
1991 } 2049 }
1992 2050
2051 enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
2052 enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
2053
1993 netdev->netdev_ops = &enic_netdev_ops; 2054 netdev->netdev_ops = &enic_netdev_ops;
1994 netdev->watchdog_timeo = 2 * HZ; 2055 netdev->watchdog_timeo = 2 * HZ;
1995 netdev->ethtool_ops = &enic_ethtool_ops; 2056 netdev->ethtool_ops = &enic_ethtool_ops;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index a605da1475c6..02839bf0fe8b 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -66,9 +66,9 @@ int enic_get_vnic_config(struct enic *enic)
66 GET_CONFIG(wq_desc_count); 66 GET_CONFIG(wq_desc_count);
67 GET_CONFIG(rq_desc_count); 67 GET_CONFIG(rq_desc_count);
68 GET_CONFIG(mtu); 68 GET_CONFIG(mtu);
69 GET_CONFIG(intr_timer);
70 GET_CONFIG(intr_timer_type); 69 GET_CONFIG(intr_timer_type);
71 GET_CONFIG(intr_mode); 70 GET_CONFIG(intr_mode);
71 GET_CONFIG(intr_timer_usec);
72 72
73 c->wq_desc_count = 73 c->wq_desc_count =
74 min_t(u32, ENIC_MAX_WQ_DESCS, 74 min_t(u32, ENIC_MAX_WQ_DESCS,
@@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic)
88 max_t(u16, ENIC_MIN_MTU, 88 max_t(u16, ENIC_MIN_MTU,
89 c->mtu)); 89 c->mtu));
90 90
91 c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); 91 c->intr_timer_usec = min_t(u32,
92 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
93 c->intr_timer_usec);
92 94
93 printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", 95 printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
94 enic->mac_addr, c->wq_desc_count, c->rq_desc_count); 96 enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
95 printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " 97 printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
96 "intr timer %d\n", 98 "intr timer %d usec\n",
97 c->mtu, ENIC_SETTING(enic, TXCSUM), 99 c->mtu, ENIC_SETTING(enic, TXCSUM),
98 ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO), 100 ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
99 ENIC_SETTING(enic, LRO), c->intr_timer); 101 ENIC_SETTING(enic, LRO), c->intr_timer_usec);
100 102
101 return 0; 103 return 0;
102} 104}
@@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic)
303 305
304 for (i = 0; i < enic->intr_count; i++) { 306 for (i = 0; i < enic->intr_count; i++) {
305 vnic_intr_init(&enic->intr[i], 307 vnic_intr_init(&enic->intr[i],
306 enic->config.intr_timer, 308 INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
307 enic->config.intr_timer_type, 309 enic->config.intr_timer_type,
308 mask_on_assertion); 310 mask_on_assertion);
309 } 311 }
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 6332ac9391b8..8eeb6758491b 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -20,6 +20,10 @@
20#ifndef _VNIC_ENIC_H_ 20#ifndef _VNIC_ENIC_H_
21#define _VNIC_ENIC_H_ 21#define _VNIC_ENIC_H_
22 22
23/* Hardware intr coalesce timer is in units of 1.5us */
24#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
25#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
26
23/* Device-specific region: enet configuration */ 27/* Device-specific region: enet configuration */
24struct vnic_enet_config { 28struct vnic_enet_config {
25 u32 flags; 29 u32 flags;
@@ -30,6 +34,7 @@ struct vnic_enet_config {
30 u8 intr_timer_type; 34 u8 intr_timer_type;
31 u8 intr_mode; 35 u8 intr_mode;
32 char devname[16]; 36 char devname[16];
37 u32 intr_timer_usec;
33}; 38};
34 39
35#define VENETF_TSO 0x1 /* TSO enabled */ 40#define VENETF_TSO 0x1 /* TSO enabled */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 1f8786d7195e..3934309a9498 100644
--- a/drivers/net/enic/vnic_intr.c
+++ b/drivers/net/enic/vnic_intr.c
@@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
50void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, 50void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
51 unsigned int coalescing_type, unsigned int mask_on_assertion) 51 unsigned int coalescing_type, unsigned int mask_on_assertion)
52{ 52{
53 iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); 53 vnic_intr_coalescing_timer_set(intr, coalescing_timer);
54 iowrite32(coalescing_type, &intr->ctrl->coalescing_type); 54 iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
55 iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); 55 iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
56 iowrite32(0, &intr->ctrl->int_credits); 56 iowrite32(0, &intr->ctrl->int_credits);
57} 57}
58 58
59void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
60 unsigned int coalescing_timer)
61{
62 iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
63}
64
59void vnic_intr_clean(struct vnic_intr *intr) 65void vnic_intr_clean(struct vnic_intr *intr)
60{ 66{
61 iowrite32(0, &intr->ctrl->int_credits); 67 iowrite32(0, &intr->ctrl->int_credits);
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index f79a722b6a03..2fe6c6339e3c 100644
--- a/drivers/net/enic/vnic_intr.h
+++ b/drivers/net/enic/vnic_intr.h
@@ -102,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
102 unsigned int index); 102 unsigned int index);
103void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, 103void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
104 unsigned int coalescing_type, unsigned int mask_on_assertion); 104 unsigned int coalescing_type, unsigned int mask_on_assertion);
105void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
106 unsigned int coalescing_timer);
105void vnic_intr_clean(struct vnic_intr *intr); 107void vnic_intr_clean(struct vnic_intr *intr);
106 108
107#endif /* _VNIC_INTR_H_ */ 109#endif /* _VNIC_INTR_H_ */