Patchwork [net-next,5/6] enic: feature add: add ethtool -c/C support

login
register
mail settings
Submitter Scott Feldman
Date Dec. 22, 2009, 2:21 a.m.
Message ID <20091222022147.30220.42433.stgit@savbu-pc100.cisco.com>
Download mbox | patch
Permalink /patch/41581/
State Superseded
Delegated to: David Miller
Headers show

Comments

Scott Feldman - Dec. 22, 2009, 2:21 a.m.
From: Scott Feldman <scofeldm@cisco.com>

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>
---
 drivers/net/enic/enic.h      |    2 +
 drivers/net/enic/enic_main.c |   65 +++++++++++++++++++++++++++++++++++++++++-
 drivers/net/enic/enic_res.c  |   12 +++++---
 drivers/net/enic/vnic_enet.h |    5 +++
 drivers/net/enic/vnic_intr.c |    8 +++++
 drivers/net/enic/vnic_intr.h |    2 +
 6 files changed, 86 insertions(+), 8 deletions(-)


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Simon Horman - Dec. 22, 2009, 5:47 a.m.
On Mon, Dec 21, 2009 at 06:21:47PM -0800, Scott Feldman wrote:
> From: Scott Feldman <scofeldm@cisco.com>
> 
> 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>

Reviewed-by: Simon Horman <horms@verge.net.au>

> ---
>  drivers/net/enic/enic.h      |    2 +
>  drivers/net/enic/enic_main.c |   65 +++++++++++++++++++++++++++++++++++++++++-
>  drivers/net/enic/enic_res.c  |   12 +++++---
>  drivers/net/enic/vnic_enet.h |    5 +++
>  drivers/net/enic/vnic_intr.c |    8 +++++
>  drivers/net/enic/vnic_intr.h |    2 +
>  6 files changed, 86 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
> index b090d65..ee01f5a 100644
> --- a/drivers/net/enic/enic.h
> +++ b/drivers/net/enic/enic.h
> @@ -93,6 +93,8 @@ struct enic {
>  	unsigned int mc_count;
>  	int csum_rx_enabled;
>  	u32 port_mtu;
> +	u32 rx_coalesce_usecs;
> +	u32 tx_coalesce_usecs;
>  
>  	/* work queue cache line section */
>  	____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 019b148..81cc68d 100644
> --- a/drivers/net/enic/enic_main.c
> +++ b/drivers/net/enic/enic_main.c
> @@ -261,7 +261,63 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
>  	enic->msg_enable = value;
>  }
>  
> -static const struct ethtool_ops enic_ethtool_ops = {
> +static int enic_get_coalesce(struct net_device *netdev,
> +	struct ethtool_coalesce *ecmd)
> +{
> +	struct enic *enic = netdev_priv(netdev);
> +
> +	ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
> +	ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
> +
> +	return 0;
> +}
> +
> +static int enic_set_coalesce(struct net_device *netdev,
> +	struct ethtool_coalesce *ecmd)
> +{
> +	struct enic *enic = netdev_priv(netdev);
> +	u32 tx_coalesce_usecs;
> +	u32 rx_coalesce_usecs;
> +
> +	tx_coalesce_usecs = min_t(u32,
> +		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
> +		ecmd->tx_coalesce_usecs);
> +	rx_coalesce_usecs = min_t(u32,
> +		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
> +		ecmd->rx_coalesce_usecs);
> +
> +	switch (vnic_dev_get_intr_mode(enic->vdev)) {
> +	case VNIC_DEV_INTR_MODE_INTX:
> +		if (tx_coalesce_usecs != rx_coalesce_usecs)
> +			return -EINVAL;
> +
> +		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
> +			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
> +		break;
> +	case VNIC_DEV_INTR_MODE_MSI:
> +		if (tx_coalesce_usecs != rx_coalesce_usecs)
> +			return -EINVAL;
> +
> +		vnic_intr_coalescing_timer_set(&enic->intr[0],
> +			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
> +		break;
> +	case VNIC_DEV_INTR_MODE_MSIX:
> +		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
> +			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
> +		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
> +			INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	enic->tx_coalesce_usecs = tx_coalesce_usecs;
> +	enic->rx_coalesce_usecs = rx_coalesce_usecs;
> +
> +	return 0;
> +}
> +
> +static struct ethtool_ops enic_ethtool_ops = {
>  	.get_settings = enic_get_settings,
>  	.get_drvinfo = enic_get_drvinfo,
>  	.get_msglevel = enic_get_msglevel,
> @@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
>  	.set_sg = ethtool_op_set_sg,
>  	.get_tso = ethtool_op_get_tso,
>  	.set_tso = enic_set_tso,
> +	.get_coalesce = enic_get_coalesce,
> +	.set_coalesce = enic_set_coalesce,
>  	.get_flags = ethtool_op_get_flags,
>  	.set_flags = ethtool_op_set_flags,
>  };
> @@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
>  	u32 mtu = vnic_dev_mtu(enic->vdev);
>  
>  	if (mtu && mtu != enic->port_mtu) {
> +		enic->port_mtu = mtu;
>  		if (mtu < enic->netdev->mtu)
>  			printk(KERN_WARNING PFX
>  				"%s: interface MTU (%d) set higher "
>  				"than switch port MTU (%d)\n",
>  				enic->netdev->name, enic->netdev->mtu, mtu);
> -		enic->port_mtu = mtu;
>  	}
>  }
>  
> @@ -1990,6 +2048,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
>  		goto err_out_dev_deinit;
>  	}
>  
> +	enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
> +	enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
> +
>  	netdev->netdev_ops = &enic_netdev_ops;
>  	netdev->watchdog_timeo = 2 * HZ;
>  	netdev->ethtool_ops = &enic_ethtool_ops;
> diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
> index a605da1..02839bf 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)
>  	GET_CONFIG(wq_desc_count);
>  	GET_CONFIG(rq_desc_count);
>  	GET_CONFIG(mtu);
> -	GET_CONFIG(intr_timer);
>  	GET_CONFIG(intr_timer_type);
>  	GET_CONFIG(intr_mode);
> +	GET_CONFIG(intr_timer_usec);
>  
>  	c->wq_desc_count =
>  		min_t(u32, ENIC_MAX_WQ_DESCS,
> @@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic)
>  		max_t(u16, ENIC_MIN_MTU,
>  		c->mtu));
>  
> -	c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
> +	c->intr_timer_usec = min_t(u32,
> +		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
> +		c->intr_timer_usec);
>  
>  	printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
>  		enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
>  	printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
> -		"intr timer %d\n",
> +		"intr timer %d usec\n",
>  		c->mtu, ENIC_SETTING(enic, TXCSUM),
>  		ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
> -		ENIC_SETTING(enic, LRO), c->intr_timer);
> +		ENIC_SETTING(enic, LRO), c->intr_timer_usec);
>  
>  	return 0;
>  }
> @@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic)
>  
>  	for (i = 0; i < enic->intr_count; i++) {
>  		vnic_intr_init(&enic->intr[i],
> -			enic->config.intr_timer,
> +			INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
>  			enic->config.intr_timer_type,
>  			mask_on_assertion);
>  	}
> diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
> index 6332ac9..8eeb675 100644
> --- a/drivers/net/enic/vnic_enet.h
> +++ b/drivers/net/enic/vnic_enet.h
> @@ -20,6 +20,10 @@
>  #ifndef _VNIC_ENIC_H_
>  #define _VNIC_ENIC_H_
>  
> +/* Hardware intr coalesce timer is in units of 1.5us */
> +#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
> +#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
> +
>  /* Device-specific region: enet configuration */
>  struct vnic_enet_config {
>  	u32 flags;
> @@ -30,6 +34,7 @@ struct vnic_enet_config {
>  	u8 intr_timer_type;
>  	u8 intr_mode;
>  	char devname[16];
> +	u32 intr_timer_usec;
>  };
>  
>  #define VENETF_TSO		0x1	/* TSO enabled */
> diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
> index 1f8786d..3934309 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,
>  void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
>  	unsigned int coalescing_type, unsigned int mask_on_assertion)
>  {
> -	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
> +	vnic_intr_coalescing_timer_set(intr, coalescing_timer);
>  	iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
>  	iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
>  	iowrite32(0, &intr->ctrl->int_credits);
>  }
>  
> +void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
> +	unsigned int coalescing_timer)
> +{
> +	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
> +}
> +
>  void vnic_intr_clean(struct vnic_intr *intr)
>  {
>  	iowrite32(0, &intr->ctrl->int_credits);
> diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
> index f79a722..2fe6c63 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,
>  	unsigned int index);
>  void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
>  	unsigned int coalescing_type, unsigned int mask_on_assertion);
> +void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
> +	unsigned int coalescing_timer);
>  void vnic_intr_clean(struct vnic_intr *intr);
>  
>  #endif /* _VNIC_INTR_H_ */
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Hutchings - Dec. 23, 2009, 6:13 p.m.
On Mon, 2009-12-21 at 18:21 -0800, Scott Feldman wrote:
> From: Scott Feldman <scofeldm@cisco.com>
> 
> 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.
[...]
> diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
> index 019b148..81cc68d 100644
> --- a/drivers/net/enic/enic_main.c
> +++ b/drivers/net/enic/enic_main.c
> @@ -261,7 +261,63 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
>  	enic->msg_enable = value;
>  }
>  
> -static const struct ethtool_ops enic_ethtool_ops = {
[...]
> +static struct ethtool_ops enic_ethtool_ops = {
[...]

I don't see any reason to remove the const here.  Is that an accidental
change?

Ben.
Scott Feldman - Dec. 23, 2009, 7:15 p.m.
On 12/23/09 10:13 AM, "Ben Hutchings" <bhutchings@solarflare.com> wrote:

> On Mon, 2009-12-21 at 18:21 -0800, Scott Feldman wrote:
>> From: Scott Feldman <scofeldm@cisco.com>
>> 
>> 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.
> [...]
>> diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
>> index 019b148..81cc68d 100644
>> --- a/drivers/net/enic/enic_main.c
>> +++ b/drivers/net/enic/enic_main.c
>> @@ -261,7 +261,63 @@ static void enic_set_msglevel(struct net_device *netdev,
>> u32 value)
>> enic->msg_enable = value;
>>  }
>>  
>> -static const struct ethtool_ops enic_ethtool_ops = {
> [...]
>> +static struct ethtool_ops enic_ethtool_ops = {
> [...]
> 
> I don't see any reason to remove the const here.  Is that an accidental
> change?

That was a mistake.  Sigh.  Let me resend patch set without that change...

[I'll wait a while in case there are any more review comments]

-scott

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index b090d65..ee01f5a 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -93,6 +93,8 @@  struct enic {
 	unsigned int mc_count;
 	int csum_rx_enabled;
 	u32 port_mtu;
+	u32 rx_coalesce_usecs;
+	u32 tx_coalesce_usecs;
 
 	/* work queue cache line section */
 	____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 019b148..81cc68d 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -261,7 +261,63 @@  static void enic_set_msglevel(struct net_device *netdev, u32 value)
 	enic->msg_enable = value;
 }
 
-static const struct ethtool_ops enic_ethtool_ops = {
+static int enic_get_coalesce(struct net_device *netdev,
+	struct ethtool_coalesce *ecmd)
+{
+	struct enic *enic = netdev_priv(netdev);
+
+	ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
+	ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
+
+	return 0;
+}
+
+static int enic_set_coalesce(struct net_device *netdev,
+	struct ethtool_coalesce *ecmd)
+{
+	struct enic *enic = netdev_priv(netdev);
+	u32 tx_coalesce_usecs;
+	u32 rx_coalesce_usecs;
+
+	tx_coalesce_usecs = min_t(u32,
+		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+		ecmd->tx_coalesce_usecs);
+	rx_coalesce_usecs = min_t(u32,
+		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+		ecmd->rx_coalesce_usecs);
+
+	switch (vnic_dev_get_intr_mode(enic->vdev)) {
+	case VNIC_DEV_INTR_MODE_INTX:
+		if (tx_coalesce_usecs != rx_coalesce_usecs)
+			return -EINVAL;
+
+		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
+			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+		break;
+	case VNIC_DEV_INTR_MODE_MSI:
+		if (tx_coalesce_usecs != rx_coalesce_usecs)
+			return -EINVAL;
+
+		vnic_intr_coalescing_timer_set(&enic->intr[0],
+			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+		break;
+	case VNIC_DEV_INTR_MODE_MSIX:
+		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
+			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+		vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
+			INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+		break;
+	default:
+		break;
+	}
+
+	enic->tx_coalesce_usecs = tx_coalesce_usecs;
+	enic->rx_coalesce_usecs = rx_coalesce_usecs;
+
+	return 0;
+}
+
+static struct ethtool_ops enic_ethtool_ops = {
 	.get_settings = enic_get_settings,
 	.get_drvinfo = enic_get_drvinfo,
 	.get_msglevel = enic_get_msglevel,
@@ -278,6 +334,8 @@  static const struct ethtool_ops enic_ethtool_ops = {
 	.set_sg = ethtool_op_set_sg,
 	.get_tso = ethtool_op_get_tso,
 	.set_tso = enic_set_tso,
+	.get_coalesce = enic_get_coalesce,
+	.set_coalesce = enic_set_coalesce,
 	.get_flags = ethtool_op_get_flags,
 	.set_flags = ethtool_op_set_flags,
 };
@@ -363,12 +421,12 @@  static void enic_mtu_check(struct enic *enic)
 	u32 mtu = vnic_dev_mtu(enic->vdev);
 
 	if (mtu && mtu != enic->port_mtu) {
+		enic->port_mtu = mtu;
 		if (mtu < enic->netdev->mtu)
 			printk(KERN_WARNING PFX
 				"%s: interface MTU (%d) set higher "
 				"than switch port MTU (%d)\n",
 				enic->netdev->name, enic->netdev->mtu, mtu);
-		enic->port_mtu = mtu;
 	}
 }
 
@@ -1990,6 +2048,9 @@  static int __devinit enic_probe(struct pci_dev *pdev,
 		goto err_out_dev_deinit;
 	}
 
+	enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
+	enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
+
 	netdev->netdev_ops = &enic_netdev_ops;
 	netdev->watchdog_timeo = 2 * HZ;
 	netdev->ethtool_ops = &enic_ethtool_ops;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index a605da1..02839bf 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)
 	GET_CONFIG(wq_desc_count);
 	GET_CONFIG(rq_desc_count);
 	GET_CONFIG(mtu);
-	GET_CONFIG(intr_timer);
 	GET_CONFIG(intr_timer_type);
 	GET_CONFIG(intr_mode);
+	GET_CONFIG(intr_timer_usec);
 
 	c->wq_desc_count =
 		min_t(u32, ENIC_MAX_WQ_DESCS,
@@ -88,15 +88,17 @@  int enic_get_vnic_config(struct enic *enic)
 		max_t(u16, ENIC_MIN_MTU,
 		c->mtu));
 
-	c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
+	c->intr_timer_usec = min_t(u32,
+		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+		c->intr_timer_usec);
 
 	printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
 		enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
 	printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
-		"intr timer %d\n",
+		"intr timer %d usec\n",
 		c->mtu, ENIC_SETTING(enic, TXCSUM),
 		ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
-		ENIC_SETTING(enic, LRO), c->intr_timer);
+		ENIC_SETTING(enic, LRO), c->intr_timer_usec);
 
 	return 0;
 }
@@ -303,7 +305,7 @@  void enic_init_vnic_resources(struct enic *enic)
 
 	for (i = 0; i < enic->intr_count; i++) {
 		vnic_intr_init(&enic->intr[i],
-			enic->config.intr_timer,
+			INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
 			enic->config.intr_timer_type,
 			mask_on_assertion);
 	}
diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h
index 6332ac9..8eeb675 100644
--- a/drivers/net/enic/vnic_enet.h
+++ b/drivers/net/enic/vnic_enet.h
@@ -20,6 +20,10 @@ 
 #ifndef _VNIC_ENIC_H_
 #define _VNIC_ENIC_H_
 
+/* Hardware intr coalesce timer is in units of 1.5us */
+#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
+#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
+
 /* Device-specific region: enet configuration */
 struct vnic_enet_config {
 	u32 flags;
@@ -30,6 +34,7 @@  struct vnic_enet_config {
 	u8 intr_timer_type;
 	u8 intr_mode;
 	char devname[16];
+	u32 intr_timer_usec;
 };
 
 #define VENETF_TSO		0x1	/* TSO enabled */
diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c
index 1f8786d..3934309 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,
 void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
 	unsigned int coalescing_type, unsigned int mask_on_assertion)
 {
-	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+	vnic_intr_coalescing_timer_set(intr, coalescing_timer);
 	iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
 	iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
 	iowrite32(0, &intr->ctrl->int_credits);
 }
 
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+	unsigned int coalescing_timer)
+{
+	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
+}
+
 void vnic_intr_clean(struct vnic_intr *intr)
 {
 	iowrite32(0, &intr->ctrl->int_credits);
diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h
index f79a722..2fe6c63 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,
 	unsigned int index);
 void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
 	unsigned int coalescing_type, unsigned int mask_on_assertion);
+void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
+	unsigned int coalescing_timer);
 void vnic_intr_clean(struct vnic_intr *intr);
 
 #endif /* _VNIC_INTR_H_ */