diff options
| author | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
| commit | 0a2d31b62dba9b5b92a38c67c9cc42630513662a (patch) | |
| tree | f755d74ec85248de645e10c45ed1a2ed467530f6 /drivers/net/enic | |
| parent | 8039290a91c5dc4414093c086987a5d7738fe2fd (diff) | |
| parent | df944f66784e6d4f2f50739263a4947885d8b6ae (diff) | |
Merge branch 'fix/kconfig' into for-linus
Diffstat (limited to 'drivers/net/enic')
| -rw-r--r-- | drivers/net/enic/enic.h | 4 | ||||
| -rw-r--r-- | drivers/net/enic/enic_dev.c | 11 | ||||
| -rw-r--r-- | drivers/net/enic/enic_dev.h | 1 | ||||
| -rw-r--r-- | drivers/net/enic/enic_main.c | 153 | ||||
| -rw-r--r-- | drivers/net/enic/enic_res.c | 30 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_cq.c | 2 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_cq.h | 1 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_dev.c | 60 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_dev.h | 5 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_devcmd.h | 19 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_enet.h | 11 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_intr.c | 7 | ||||
| -rw-r--r-- | drivers/net/enic/vnic_intr.h | 6 | 
13 files changed, 237 insertions, 73 deletions
| diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 38b351c7b979..ce76d9a8ca6e 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@  #define DRV_NAME		"enic"  #define DRV_DESCRIPTION		"Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION		"2.1.1.13" +#define DRV_VERSION		"2.1.1.24"  #define DRV_COPYRIGHT		"Copyright 2008-2011 Cisco Systems, Inc"  #define ENIC_BARS_MAX		6 @@ -74,6 +74,7 @@ struct enic {  	struct vnic_dev *vdev;  	struct timer_list notify_timer;  	struct work_struct reset; +	struct work_struct change_mtu_work;  	struct msix_entry msix_entry[ENIC_INTR_MAX];  	struct enic_msix_entry msix[ENIC_INTR_MAX];  	u32 msg_enable; @@ -93,7 +94,6 @@ struct enic {  	____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];  	spinlock_t wq_lock[ENIC_WQ_MAX];  	unsigned int wq_count; -	struct vlan_group *vlan_group;  	u16 loop_enable;  	u16 loop_tag; diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c index 90687b14e60f..fd6247b3c0ee 100644 --- a/drivers/net/enic/enic_dev.c +++ b/drivers/net/enic/enic_dev.c @@ -166,6 +166,17 @@ int enic_dev_disable(struct enic *enic)  	return err;  } +int enic_dev_intr_coal_timer_info(struct enic *enic) +{ +	int err; + +	spin_lock(&enic->devcmd_lock); +	err = vnic_dev_intr_coal_timer_info(enic->vdev); +	spin_unlock(&enic->devcmd_lock); + +	return err; +} +  int enic_vnic_dev_deinit(struct enic *enic)  {  	int err; diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h index d5f681337626..ff8e87fdfc1d 100644 --- a/drivers/net/enic/enic_dev.h +++ b/drivers/net/enic/enic_dev.h @@ -34,6 +34,7 @@ int enic_dev_hang_notify(struct enic *enic);  int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);  int enic_dev_enable(struct enic *enic);  int enic_dev_disable(struct enic *enic); +int enic_dev_intr_coal_timer_info(struct enic *enic);  int enic_vnic_dev_deinit(struct enic *enic);  int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp);  int enic_dev_deinit_done(struct enic *enic, int *status); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2f433fbfca0c..67a27cd304dd 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -23,6 +23,7 @@  #include <linux/errno.h>  #include <linux/types.h>  #include <linux/init.h> +#include <linux/interrupt.h>  #include <linux/workqueue.h>  #include <linux/pci.h>  #include <linux/netdevice.h> @@ -152,12 +153,12 @@ static inline unsigned int enic_legacy_notify_intr(void)  static inline unsigned int enic_msix_rq_intr(struct enic *enic, unsigned int rq)  { -	return rq; +	return enic->cq[enic_cq_rq(enic, rq)].interrupt_offset;  }  static inline unsigned int enic_msix_wq_intr(struct enic *enic, unsigned int wq)  { -	return enic->rq_count + wq; +	return enic->cq[enic_cq_wq(enic, wq)].interrupt_offset;  }  static inline unsigned int enic_msix_err_intr(struct enic *enic) @@ -283,12 +284,10 @@ static int enic_set_coalesce(struct net_device *netdev,  	u32 rx_coalesce_usecs;  	unsigned int i, intr; -	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); +	tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, +		vnic_dev_get_intr_coal_timer_max(enic->vdev)); +	rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, +		vnic_dev_get_intr_coal_timer_max(enic->vdev));  	switch (vnic_dev_get_intr_mode(enic->vdev)) {  	case VNIC_DEV_INTR_MODE_INTX: @@ -297,26 +296,26 @@ static int enic_set_coalesce(struct net_device *netdev,  		intr = enic_legacy_io_intr();  		vnic_intr_coalescing_timer_set(&enic->intr[intr], -			INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); +			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)); +			tx_coalesce_usecs);  		break;  	case VNIC_DEV_INTR_MODE_MSIX:  		for (i = 0; i < enic->wq_count; i++) {  			intr = enic_msix_wq_intr(enic, i);  			vnic_intr_coalescing_timer_set(&enic->intr[intr], -				INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); +				tx_coalesce_usecs);  		}  		for (i = 0; i < enic->rq_count; i++) {  			intr = enic_msix_rq_intr(enic, i);  			vnic_intr_coalescing_timer_set(&enic->intr[intr], -				INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs)); +				rx_coalesce_usecs);  		}  		break; @@ -423,11 +422,18 @@ static void enic_mtu_check(struct enic *enic)  	if (mtu && mtu != enic->port_mtu) {  		enic->port_mtu = mtu; -		if (mtu < netdev->mtu) -			netdev_warn(netdev, -				"interface MTU (%d) set higher " -				"than switch port MTU (%d)\n", -				netdev->mtu, mtu); +		if (enic_is_dynamic(enic)) { +			mtu = max_t(int, ENIC_MIN_MTU, +				min_t(int, ENIC_MAX_MTU, mtu)); +			if (mtu != netdev->mtu) +				schedule_work(&enic->change_mtu_work); +		} else { +			if (mtu < netdev->mtu) +				netdev_warn(netdev, +					"interface MTU (%d) set higher " +					"than switch port MTU (%d)\n", +					netdev->mtu, mtu); +		}  	}  } @@ -793,10 +799,10 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,  }  /* dev_base_lock rwlock held, nominally process context */ -static struct net_device_stats *enic_get_stats(struct net_device *netdev) +static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev, +						struct rtnl_link_stats64 *net_stats)  {  	struct enic *enic = netdev_priv(netdev); -	struct net_device_stats *net_stats = &netdev->stats;  	struct vnic_stats *stats;  	enic_dev_stats_dump(enic, &stats); @@ -1023,14 +1029,6 @@ static void enic_set_rx_mode(struct net_device *netdev)  	}  } -/* rtnl lock is held */ -static void enic_vlan_rx_register(struct net_device *netdev, -	struct vlan_group *vlan_group) -{ -	struct enic *enic = netdev_priv(netdev); -	enic->vlan_group = vlan_group; -} -  /* netif_tx_lock held, BHs disabled */  static void enic_tx_timeout(struct net_device *netdev)  { @@ -1258,24 +1256,13 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,  		skb->dev = netdev; -		if (enic->vlan_group && vlan_stripped && -			(vlan_tci & CQ_ENET_RQ_DESC_VLAN_TCI_VLAN_MASK)) { - -			if (netdev->features & NETIF_F_GRO) -				vlan_gro_receive(&enic->napi[q_number], -					enic->vlan_group, vlan_tci, skb); -			else -				vlan_hwaccel_receive_skb(skb, -					enic->vlan_group, vlan_tci); - -		} else { +		if (vlan_stripped) +			__vlan_hwaccel_put_tag(skb, vlan_tci); -			if (netdev->features & NETIF_F_GRO) -				napi_gro_receive(&enic->napi[q_number], skb); -			else -				netif_receive_skb(skb); - -		} +		if (netdev->features & NETIF_F_GRO) +			napi_gro_receive(&enic->napi[q_number], skb); +		else +			netif_receive_skb(skb);  	} else {  		/* Buffer overflow @@ -1560,7 +1547,7 @@ static void enic_notify_timer_start(struct enic *enic)  	default:  		/* Using intr for notification for INTx/MSI-X */  		break; -	}; +	}  }  /* rtnl lock is held, process context */ @@ -1688,6 +1675,9 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)  	if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU)  		return -EINVAL; +	if (enic_is_dynamic(enic)) +		return -EOPNOTSUPP; +  	if (running)  		enic_stop(netdev); @@ -1704,6 +1694,55 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)  	return 0;  } +static void enic_change_mtu_work(struct work_struct *work) +{ +	struct enic *enic = container_of(work, struct enic, change_mtu_work); +	struct net_device *netdev = enic->netdev; +	int new_mtu = vnic_dev_mtu(enic->vdev); +	int err; +	unsigned int i; + +	new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu)); + +	rtnl_lock(); + +	/* Stop RQ */ +	del_timer_sync(&enic->notify_timer); + +	for (i = 0; i < enic->rq_count; i++) +		napi_disable(&enic->napi[i]); + +	vnic_intr_mask(&enic->intr[0]); +	enic_synchronize_irqs(enic); +	err = vnic_rq_disable(&enic->rq[0]); +	if (err) { +		netdev_err(netdev, "Unable to disable RQ.\n"); +		return; +	} +	vnic_rq_clean(&enic->rq[0], enic_free_rq_buf); +	vnic_cq_clean(&enic->cq[0]); +	vnic_intr_clean(&enic->intr[0]); + +	/* Fill RQ with new_mtu-sized buffers */ +	netdev->mtu = new_mtu; +	vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); +	/* Need at least one buffer on ring to get going */ +	if (vnic_rq_desc_used(&enic->rq[0]) == 0) { +		netdev_err(netdev, "Unable to alloc receive buffers.\n"); +		return; +	} + +	/* Start RQ */ +	vnic_rq_enable(&enic->rq[0]); +	napi_enable(&enic->napi[0]); +	vnic_intr_unmask(&enic->intr[0]); +	enic_notify_timer_start(enic); + +	rtnl_unlock(); + +	netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu); +} +  #ifdef CONFIG_NET_POLL_CONTROLLER  static void enic_poll_controller(struct net_device *netdev)  { @@ -1718,8 +1757,12 @@ static void enic_poll_controller(struct net_device *netdev)  			enic_isr_msix_rq(enic->msix_entry[intr].vector,  				&enic->napi[i]);  		} -		intr = enic_msix_wq_intr(enic, i); -		enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); + +		for (i = 0; i < enic->wq_count; i++) { +			intr = enic_msix_wq_intr(enic, i); +			enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); +		} +  		break;  	case VNIC_DEV_INTR_MODE_MSI:  		enic_isr_msi(enic->pdev->irq, enic); @@ -2057,13 +2100,12 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {  	.ndo_open		= enic_open,  	.ndo_stop		= enic_stop,  	.ndo_start_xmit		= enic_hard_start_xmit, -	.ndo_get_stats		= enic_get_stats, +	.ndo_get_stats64	= enic_get_stats,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_rx_mode	= enic_set_rx_mode,  	.ndo_set_multicast_list	= enic_set_rx_mode,  	.ndo_set_mac_address	= enic_set_mac_address_dynamic,  	.ndo_change_mtu		= enic_change_mtu, -	.ndo_vlan_rx_register	= enic_vlan_rx_register,  	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,  	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,  	.ndo_tx_timeout		= enic_tx_timeout, @@ -2079,13 +2121,12 @@ static const struct net_device_ops enic_netdev_ops = {  	.ndo_open		= enic_open,  	.ndo_stop		= enic_stop,  	.ndo_start_xmit		= enic_hard_start_xmit, -	.ndo_get_stats		= enic_get_stats, +	.ndo_get_stats64	= enic_get_stats,  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_set_mac_address	= enic_set_mac_address,  	.ndo_set_rx_mode	= enic_set_rx_mode,  	.ndo_set_multicast_list	= enic_set_rx_mode,  	.ndo_change_mtu		= enic_change_mtu, -	.ndo_vlan_rx_register	= enic_vlan_rx_register,  	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,  	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,  	.ndo_tx_timeout		= enic_tx_timeout, @@ -2112,6 +2153,14 @@ static int enic_dev_init(struct enic *enic)  	unsigned int i;  	int err; +	/* Get interrupt coalesce timer info */ +	err = enic_dev_intr_coal_timer_info(enic); +	if (err) { +		dev_warn(dev, "Using default conversion factor for " +			"interrupt coalesce timer\n"); +		vnic_dev_intr_coal_timer_info_default(enic->vdev); +	} +  	/* Get vNIC configuration  	 */ @@ -2345,6 +2394,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,  	enic->notify_timer.data = (unsigned long)enic;  	INIT_WORK(&enic->reset, enic_reset); +	INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);  	for (i = 0; i < enic->wq_count; i++)  		spin_lock_init(&enic->wq_lock[i]); @@ -2427,6 +2477,7 @@ static void __devexit enic_remove(struct pci_dev *pdev)  		struct enic *enic = netdev_priv(netdev);  		cancel_work_sync(&enic->reset); +		cancel_work_sync(&enic->change_mtu_work);  		unregister_netdev(netdev);  		enic_dev_deinit(enic);  		vnic_dev_close(enic->vdev); diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 6e5c6356e7df..4a35367de790 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -90,18 +90,30 @@ int enic_get_vnic_config(struct enic *enic)  		max_t(u16, ENIC_MIN_MTU,  		c->mtu)); -	c->intr_timer_usec = min_t(u32, -		INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), -		c->intr_timer_usec); +	c->intr_timer_usec = min_t(u32, c->intr_timer_usec, +		vnic_dev_get_intr_coal_timer_max(enic->vdev));  	dev_info(enic_get_dev(enic),  		"vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",  		enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu); -	dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d " -		"tso %d intr timer %d usec rss %d\n", -		ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM), -		ENIC_SETTING(enic, TSO), -		c->intr_timer_usec, ENIC_SETTING(enic, RSS)); + +	dev_info(enic_get_dev(enic), "vNIC csum tx/rx %s/%s " +		"tso/lro %s/%s rss %s intr mode %s type %s timer %d usec " +		"loopback tag 0x%04x\n", +		ENIC_SETTING(enic, TXCSUM) ? "yes" : "no", +		ENIC_SETTING(enic, RXCSUM) ? "yes" : "no", +		ENIC_SETTING(enic, TSO) ? "yes" : "no", +		ENIC_SETTING(enic, LRO) ? "yes" : "no", +		ENIC_SETTING(enic, RSS) ? "yes" : "no", +		c->intr_mode == VENET_INTR_MODE_INTX ? "INTx" : +		c->intr_mode == VENET_INTR_MODE_MSI ? "MSI" : +		c->intr_mode == VENET_INTR_MODE_ANY ? "any" : +		"unknown", +		c->intr_timer_type == VENET_INTR_TYPE_MIN ? "min" : +		c->intr_timer_type == VENET_INTR_TYPE_IDLE ? "idle" : +		"unknown", +		c->intr_timer_usec, +		c->loop_tag);  	return 0;  } @@ -290,7 +302,7 @@ void enic_init_vnic_resources(struct enic *enic)  	for (i = 0; i < enic->intr_count; i++) {  		vnic_intr_init(&enic->intr[i], -			INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec), +			enic->config.intr_timer_usec,  			enic->config.intr_timer_type,  			mask_on_assertion);  	} diff --git a/drivers/net/enic/vnic_cq.c b/drivers/net/enic/vnic_cq.c index b86d6ef8dad3..0daa1c7073cb 100644 --- a/drivers/net/enic/vnic_cq.c +++ b/drivers/net/enic/vnic_cq.c @@ -74,6 +74,8 @@ void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,  	iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable);  	iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset);  	writeq(cq_message_addr, &cq->ctrl->cq_message_addr); + +	cq->interrupt_offset = interrupt_offset;  }  void vnic_cq_clean(struct vnic_cq *cq) diff --git a/drivers/net/enic/vnic_cq.h b/drivers/net/enic/vnic_cq.h index 552d3daf2508..579315cbe803 100644 --- a/drivers/net/enic/vnic_cq.h +++ b/drivers/net/enic/vnic_cq.h @@ -57,6 +57,7 @@ struct vnic_cq {  	struct vnic_dev_ring ring;  	unsigned int to_clean;  	unsigned int last_color; +	unsigned int interrupt_offset;  };  static inline unsigned int vnic_cq_service(struct vnic_cq *cq, diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 68f24ae860ae..8c4c8cf486f6 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -40,6 +40,12 @@ struct vnic_res {  	unsigned int count;  }; +struct vnic_intr_coal_timer_info { +	u32 mul; +	u32 div; +	u32 max_usec; +}; +  struct vnic_dev {  	void *priv;  	struct pci_dev *pdev; @@ -58,6 +64,7 @@ struct vnic_dev {  	enum vnic_proxy_type proxy;  	u32 proxy_index;  	u64 args[VNIC_DEVCMD_NARGS]; +	struct vnic_intr_coal_timer_info intr_coal_timer_info;  };  #define VNIC_MAX_RES_HDR_SIZE \ @@ -794,6 +801,42 @@ int vnic_dev_deinit(struct vnic_dev *vdev)  	return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait);  } +void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev) +{ +	/* Default: hardware intr coal timer is in units of 1.5 usecs */ +	vdev->intr_coal_timer_info.mul = 2; +	vdev->intr_coal_timer_info.div = 3; +	vdev->intr_coal_timer_info.max_usec = +		vnic_dev_intr_coal_timer_hw_to_usec(vdev, 0xffff); +} + +int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev) +{ +	int wait = 1000; +	int err; + +	memset(vdev->args, 0, sizeof(vdev->args)); + +	err = _vnic_dev_cmd(vdev, CMD_INTR_COAL_CONVERT, wait); + +	/* Use defaults when firmware doesn't support the devcmd at all or +	 * supports it for only specific hardware +	 */ +	if ((err == ERR_ECMDUNKNOWN) || +		(!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) { +		pr_warning("Using default conversion factor for " +			"interrupt coalesce timer\n"); +		vnic_dev_intr_coal_timer_info_default(vdev); +		return 0; +	} + +	vdev->intr_coal_timer_info.mul = (u32) vdev->args[0]; +	vdev->intr_coal_timer_info.div = (u32) vdev->args[1]; +	vdev->intr_coal_timer_info.max_usec = (u32) vdev->args[2]; + +	return err; +} +  int vnic_dev_link_status(struct vnic_dev *vdev)  {  	if (!vnic_dev_notify_ready(vdev)) @@ -838,6 +881,23 @@ enum vnic_dev_intr_mode vnic_dev_get_intr_mode(  	return vdev->intr_mode;  } +u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec) +{ +	return (usec * vdev->intr_coal_timer_info.mul) / +		vdev->intr_coal_timer_info.div; +} + +u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles) +{ +	return (hw_cycles * vdev->intr_coal_timer_info.div) / +		vdev->intr_coal_timer_info.mul; +} + +u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev) +{ +	return vdev->intr_coal_timer_info.max_usec; +} +  void vnic_dev_unregister(struct vnic_dev *vdev)  {  	if (vdev) { diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index cf482a2c9dd9..852b698fbe7d 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h @@ -109,11 +109,16 @@ int vnic_dev_open(struct vnic_dev *vdev, int arg);  int vnic_dev_open_done(struct vnic_dev *vdev, int *done);  int vnic_dev_init(struct vnic_dev *vdev, int arg);  int vnic_dev_deinit(struct vnic_dev *vdev); +void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev); +int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev);  int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);  int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);  void vnic_dev_set_intr_mode(struct vnic_dev *vdev,  	enum vnic_dev_intr_mode intr_mode);  enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); +u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec); +u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles); +u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev);  void vnic_dev_unregister(struct vnic_dev *vdev);  int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,  	u8 ig_vlan_rewrite_mode); diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index c5569bfb47ac..8025e8808d61 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -318,6 +318,25 @@ enum vnic_devcmd_cmd {  	 *             ERR_EINPROGRESS - command in a0 is still in progress  	 */  	CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49), + +	/* +	 * Returns interrupt coalescing timer conversion factors. +	 * After calling this devcmd, ENIC driver can convert +	 * interrupt coalescing timer in usec into CPU cycles as follows: +	 * +	 *   intr_timer_cycles = intr_timer_usec * multiplier / divisor +	 * +	 * Interrupt coalescing timer in usecs can be obtained from +	 * CPU cycles as follows: +	 * +	 *   intr_timer_usec = intr_timer_cycles * divisor / multiplier +	 * +	 * in: none +	 * out: (u32)a0 = multiplier +	 *      (u32)a1 = divisor +	 *      (u32)a2 = maximum timer value in usec +	 */ +	CMD_INTR_COAL_CONVERT = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 50),  };  /* CMD_ENABLE2 flags */ diff --git a/drivers/net/enic/vnic_enet.h b/drivers/net/enic/vnic_enet.h index e8740e3704e4..609542848e02 100644 --- a/drivers/net/enic/vnic_enet.h +++ b/drivers/net/enic/vnic_enet.h @@ -20,10 +20,6 @@  #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; @@ -51,4 +47,11 @@ struct vnic_enet_config {  #define VENETF_RSSHASH_TCPIPV6_EX 0x400	/* Hash on TCP + IPv6 ext. fields */  #define VENETF_LOOP		0x800	/* Loopback enabled */ +#define VENET_INTR_TYPE_MIN	0	/* Timer specs min interrupt spacing */ +#define VENET_INTR_TYPE_IDLE	1	/* Timer specs idle time before irq */ + +#define VENET_INTR_MODE_ANY	0	/* Try MSI-X, then MSI, then INTx */ +#define VENET_INTR_MODE_MSI	1	/* Try MSI then INTx */ +#define VENET_INTR_MODE_INTX	2	/* Try INTx only */ +  #endif /* _VNIC_ENIC_H_ */ diff --git a/drivers/net/enic/vnic_intr.c b/drivers/net/enic/vnic_intr.c index 3873771d75cc..0ca107f7bc8c 100644 --- a/drivers/net/enic/vnic_intr.c +++ b/drivers/net/enic/vnic_intr.c @@ -46,7 +46,7 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,  	return 0;  } -void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, +void vnic_intr_init(struct vnic_intr *intr, u32 coalescing_timer,  	unsigned int coalescing_type, unsigned int mask_on_assertion)  {  	vnic_intr_coalescing_timer_set(intr, coalescing_timer); @@ -56,9 +56,10 @@ void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,  }  void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, -	unsigned int coalescing_timer) +	u32 coalescing_timer)  { -	iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); +	iowrite32(vnic_dev_intr_coal_timer_usec_to_hw(intr->vdev, +		coalescing_timer), &intr->ctrl->coalescing_timer);  }  void vnic_intr_clean(struct vnic_intr *intr) diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index 09dc0b73ff46..2b1636392294 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -24,8 +24,6 @@  #include "vnic_dev.h" -#define VNIC_INTR_TIMER_MAX		0xffff -  #define VNIC_INTR_TIMER_TYPE_ABS	0  #define VNIC_INTR_TIMER_TYPE_QUIET	1 @@ -104,10 +102,10 @@ static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)  void vnic_intr_free(struct vnic_intr *intr);  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, +void vnic_intr_init(struct vnic_intr *intr, u32 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); +	u32 coalescing_timer);  void vnic_intr_clean(struct vnic_intr *intr);  #endif /* _VNIC_INTR_H_ */ | 
