diff options
author | Scott Feldman <scofeldm@cisco.com> | 2009-12-23 08:27:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-24 00:03:41 -0500 |
commit | 7c8445991172cc17eaca9f7de0a300c02caaa49d (patch) | |
tree | 0518a514d0d3e5af0d6442a2ef72aa10bbce58ae /drivers/net/enic | |
parent | bd2496229e702b2eb50eab5589858a3cdb7847b2 (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.h | 2 | ||||
-rw-r--r-- | drivers/net/enic/enic_main.c | 63 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.c | 12 | ||||
-rw-r--r-- | drivers/net/enic/vnic_enet.h | 5 | ||||
-rw-r--r-- | drivers/net/enic/vnic_intr.c | 8 | ||||
-rw-r--r-- | drivers/net/enic/vnic_intr.h | 2 |
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 | ||
264 | static 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 | |||
275 | static 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 | |||
264 | static const struct ethtool_ops enic_ethtool_ops = { | 320 | static 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 */ |
24 | struct vnic_enet_config { | 28 | struct 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, | |||
50 | void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, | 50 | void 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 | ||
59 | void 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 | |||
59 | void vnic_intr_clean(struct vnic_intr *intr) | 65 | void 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); |
103 | void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, | 103 | void 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); |
105 | void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, | ||
106 | unsigned int coalescing_timer); | ||
105 | void vnic_intr_clean(struct vnic_intr *intr); | 107 | void vnic_intr_clean(struct vnic_intr *intr); |
106 | 108 | ||
107 | #endif /* _VNIC_INTR_H_ */ | 109 | #endif /* _VNIC_INTR_H_ */ |