diff options
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_ */ |