diff options
-rw-r--r-- | drivers/net/enic/enic.h | 2 | ||||
-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 | 26 | ||||
-rw-r--r-- | drivers/net/enic/enic_res.c | 7 | ||||
-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 | 4 | ||||
-rw-r--r-- | drivers/net/enic/vnic_intr.c | 7 | ||||
-rw-r--r-- | drivers/net/enic/vnic_intr.h | 6 |
11 files changed, 122 insertions, 26 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index f747bceb75b1..f0b062b4a223 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.20" +#define DRV_VERSION "2.1.1.24" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 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 4b3a93a924e8..e25800fa96ca 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -284,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: @@ -298,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; @@ -2175,6 +2173,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 */ diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 34f42072b60c..4a35367de790 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -90,9 +90,8 @@ 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", @@ -303,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_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 061ad8780796..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; 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_ */ |