aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/enic
diff options
context:
space:
mode:
authorVasanthy Kolluri <vkolluri@cisco.com>2011-06-17 03:56:48 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-30 23:43:38 -0400
commitea7ea65a3b37bf207d5c352ac6254506b3dc3901 (patch)
tree5eed17f071404155e7a76f8f3415bf031a4d656a /drivers/net/enic
parent3fa2a1df909482cc234524906e4bd30dee3514df (diff)
enic: Add support to configure hardware interrupt coalesce timers in a platform independent way
enic driver and the underlying hardware use different units for representing the interrupt coalesce timer. Driver converts the interrupt coalesce timer in usec to hardware cycles while setting the relevant hardware registers. The conversion factor can be different for each of the adapter hardware types. So it is dynamically learnt from the adapter firmware using the devcmd CMD_INTR_COAL_CONVERT. This allows the driver to configure the hardware interrupt coalesce timers in a platform independent way. Signed-off-by: Danny Guo <dannguo@cisco.com> Signed-off-by: Vasanthy Kolluri <vkolluri@cisco.com> Signed-off-by: Roopa Prabhu <roprabhu@cisco.com> Signed-off-by: David Wang <dwang2@cisco.com> Signed-off-by: David S. Miller <davem@conan.davemloft.net>
Diffstat (limited to 'drivers/net/enic')
-rw-r--r--drivers/net/enic/enic.h2
-rw-r--r--drivers/net/enic/enic_dev.c11
-rw-r--r--drivers/net/enic/enic_dev.h1
-rw-r--r--drivers/net/enic/enic_main.c26
-rw-r--r--drivers/net/enic/enic_res.c7
-rw-r--r--drivers/net/enic/vnic_dev.c60
-rw-r--r--drivers/net/enic/vnic_dev.h5
-rw-r--r--drivers/net/enic/vnic_devcmd.h19
-rw-r--r--drivers/net/enic/vnic_enet.h4
-rw-r--r--drivers/net/enic/vnic_intr.c7
-rw-r--r--drivers/net/enic/vnic_intr.h6
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 @@
32 32
33#define DRV_NAME "enic" 33#define DRV_NAME "enic"
34#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" 34#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
35#define DRV_VERSION "2.1.1.20" 35#define DRV_VERSION "2.1.1.24"
36#define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" 36#define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc"
37 37
38#define ENIC_BARS_MAX 6 38#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)
166 return err; 166 return err;
167} 167}
168 168
169int enic_dev_intr_coal_timer_info(struct enic *enic)
170{
171 int err;
172
173 spin_lock(&enic->devcmd_lock);
174 err = vnic_dev_intr_coal_timer_info(enic->vdev);
175 spin_unlock(&enic->devcmd_lock);
176
177 return err;
178}
179
169int enic_vnic_dev_deinit(struct enic *enic) 180int enic_vnic_dev_deinit(struct enic *enic)
170{ 181{
171 int err; 182 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);
34int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic); 34int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);
35int enic_dev_enable(struct enic *enic); 35int enic_dev_enable(struct enic *enic);
36int enic_dev_disable(struct enic *enic); 36int enic_dev_disable(struct enic *enic);
37int enic_dev_intr_coal_timer_info(struct enic *enic);
37int enic_vnic_dev_deinit(struct enic *enic); 38int enic_vnic_dev_deinit(struct enic *enic);
38int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp); 39int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp);
39int enic_dev_deinit_done(struct enic *enic, int *status); 40int 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,
284 u32 rx_coalesce_usecs; 284 u32 rx_coalesce_usecs;
285 unsigned int i, intr; 285 unsigned int i, intr;
286 286
287 tx_coalesce_usecs = min_t(u32, 287 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
288 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), 288 vnic_dev_get_intr_coal_timer_max(enic->vdev));
289 ecmd->tx_coalesce_usecs); 289 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
290 rx_coalesce_usecs = min_t(u32, 290 vnic_dev_get_intr_coal_timer_max(enic->vdev));
291 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
292 ecmd->rx_coalesce_usecs);
293 291
294 switch (vnic_dev_get_intr_mode(enic->vdev)) { 292 switch (vnic_dev_get_intr_mode(enic->vdev)) {
295 case VNIC_DEV_INTR_MODE_INTX: 293 case VNIC_DEV_INTR_MODE_INTX:
@@ -298,26 +296,26 @@ static int enic_set_coalesce(struct net_device *netdev,
298 296
299 intr = enic_legacy_io_intr(); 297 intr = enic_legacy_io_intr();
300 vnic_intr_coalescing_timer_set(&enic->intr[intr], 298 vnic_intr_coalescing_timer_set(&enic->intr[intr],
301 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); 299 tx_coalesce_usecs);
302 break; 300 break;
303 case VNIC_DEV_INTR_MODE_MSI: 301 case VNIC_DEV_INTR_MODE_MSI:
304 if (tx_coalesce_usecs != rx_coalesce_usecs) 302 if (tx_coalesce_usecs != rx_coalesce_usecs)
305 return -EINVAL; 303 return -EINVAL;
306 304
307 vnic_intr_coalescing_timer_set(&enic->intr[0], 305 vnic_intr_coalescing_timer_set(&enic->intr[0],
308 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); 306 tx_coalesce_usecs);
309 break; 307 break;
310 case VNIC_DEV_INTR_MODE_MSIX: 308 case VNIC_DEV_INTR_MODE_MSIX:
311 for (i = 0; i < enic->wq_count; i++) { 309 for (i = 0; i < enic->wq_count; i++) {
312 intr = enic_msix_wq_intr(enic, i); 310 intr = enic_msix_wq_intr(enic, i);
313 vnic_intr_coalescing_timer_set(&enic->intr[intr], 311 vnic_intr_coalescing_timer_set(&enic->intr[intr],
314 INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs)); 312 tx_coalesce_usecs);
315 } 313 }
316 314
317 for (i = 0; i < enic->rq_count; i++) { 315 for (i = 0; i < enic->rq_count; i++) {
318 intr = enic_msix_rq_intr(enic, i); 316 intr = enic_msix_rq_intr(enic, i);
319 vnic_intr_coalescing_timer_set(&enic->intr[intr], 317 vnic_intr_coalescing_timer_set(&enic->intr[intr],
320 INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs)); 318 rx_coalesce_usecs);
321 } 319 }
322 320
323 break; 321 break;
@@ -2175,6 +2173,14 @@ static int enic_dev_init(struct enic *enic)
2175 unsigned int i; 2173 unsigned int i;
2176 int err; 2174 int err;
2177 2175
2176 /* Get interrupt coalesce timer info */
2177 err = enic_dev_intr_coal_timer_info(enic);
2178 if (err) {
2179 dev_warn(dev, "Using default conversion factor for "
2180 "interrupt coalesce timer\n");
2181 vnic_dev_intr_coal_timer_info_default(enic->vdev);
2182 }
2183
2178 /* Get vNIC configuration 2184 /* Get vNIC configuration
2179 */ 2185 */
2180 2186
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)
90 max_t(u16, ENIC_MIN_MTU, 90 max_t(u16, ENIC_MIN_MTU,
91 c->mtu)); 91 c->mtu));
92 92
93 c->intr_timer_usec = min_t(u32, 93 c->intr_timer_usec = min_t(u32, c->intr_timer_usec,
94 INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX), 94 vnic_dev_get_intr_coal_timer_max(enic->vdev));
95 c->intr_timer_usec);
96 95
97 dev_info(enic_get_dev(enic), 96 dev_info(enic_get_dev(enic),
98 "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n", 97 "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
@@ -303,7 +302,7 @@ void enic_init_vnic_resources(struct enic *enic)
303 302
304 for (i = 0; i < enic->intr_count; i++) { 303 for (i = 0; i < enic->intr_count; i++) {
305 vnic_intr_init(&enic->intr[i], 304 vnic_intr_init(&enic->intr[i],
306 INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec), 305 enic->config.intr_timer_usec,
307 enic->config.intr_timer_type, 306 enic->config.intr_timer_type,
308 mask_on_assertion); 307 mask_on_assertion);
309 } 308 }
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 {
40 unsigned int count; 40 unsigned int count;
41}; 41};
42 42
43struct vnic_intr_coal_timer_info {
44 u32 mul;
45 u32 div;
46 u32 max_usec;
47};
48
43struct vnic_dev { 49struct vnic_dev {
44 void *priv; 50 void *priv;
45 struct pci_dev *pdev; 51 struct pci_dev *pdev;
@@ -58,6 +64,7 @@ struct vnic_dev {
58 enum vnic_proxy_type proxy; 64 enum vnic_proxy_type proxy;
59 u32 proxy_index; 65 u32 proxy_index;
60 u64 args[VNIC_DEVCMD_NARGS]; 66 u64 args[VNIC_DEVCMD_NARGS];
67 struct vnic_intr_coal_timer_info intr_coal_timer_info;
61}; 68};
62 69
63#define VNIC_MAX_RES_HDR_SIZE \ 70#define VNIC_MAX_RES_HDR_SIZE \
@@ -794,6 +801,42 @@ int vnic_dev_deinit(struct vnic_dev *vdev)
794 return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait); 801 return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait);
795} 802}
796 803
804void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev)
805{
806 /* Default: hardware intr coal timer is in units of 1.5 usecs */
807 vdev->intr_coal_timer_info.mul = 2;
808 vdev->intr_coal_timer_info.div = 3;
809 vdev->intr_coal_timer_info.max_usec =
810 vnic_dev_intr_coal_timer_hw_to_usec(vdev, 0xffff);
811}
812
813int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
814{
815 int wait = 1000;
816 int err;
817
818 memset(vdev->args, 0, sizeof(vdev->args));
819
820 err = _vnic_dev_cmd(vdev, CMD_INTR_COAL_CONVERT, wait);
821
822 /* Use defaults when firmware doesn't support the devcmd at all or
823 * supports it for only specific hardware
824 */
825 if ((err == ERR_ECMDUNKNOWN) ||
826 (!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) {
827 pr_warning("Using default conversion factor for "
828 "interrupt coalesce timer\n");
829 vnic_dev_intr_coal_timer_info_default(vdev);
830 return 0;
831 }
832
833 vdev->intr_coal_timer_info.mul = (u32) vdev->args[0];
834 vdev->intr_coal_timer_info.div = (u32) vdev->args[1];
835 vdev->intr_coal_timer_info.max_usec = (u32) vdev->args[2];
836
837 return err;
838}
839
797int vnic_dev_link_status(struct vnic_dev *vdev) 840int vnic_dev_link_status(struct vnic_dev *vdev)
798{ 841{
799 if (!vnic_dev_notify_ready(vdev)) 842 if (!vnic_dev_notify_ready(vdev))
@@ -838,6 +881,23 @@ enum vnic_dev_intr_mode vnic_dev_get_intr_mode(
838 return vdev->intr_mode; 881 return vdev->intr_mode;
839} 882}
840 883
884u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec)
885{
886 return (usec * vdev->intr_coal_timer_info.mul) /
887 vdev->intr_coal_timer_info.div;
888}
889
890u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles)
891{
892 return (hw_cycles * vdev->intr_coal_timer_info.div) /
893 vdev->intr_coal_timer_info.mul;
894}
895
896u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev)
897{
898 return vdev->intr_coal_timer_info.max_usec;
899}
900
841void vnic_dev_unregister(struct vnic_dev *vdev) 901void vnic_dev_unregister(struct vnic_dev *vdev)
842{ 902{
843 if (vdev) { 903 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);
109int vnic_dev_open_done(struct vnic_dev *vdev, int *done); 109int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
110int vnic_dev_init(struct vnic_dev *vdev, int arg); 110int vnic_dev_init(struct vnic_dev *vdev, int arg);
111int vnic_dev_deinit(struct vnic_dev *vdev); 111int vnic_dev_deinit(struct vnic_dev *vdev);
112void vnic_dev_intr_coal_timer_info_default(struct vnic_dev *vdev);
113int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev);
112int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg); 114int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
113int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done); 115int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
114void vnic_dev_set_intr_mode(struct vnic_dev *vdev, 116void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
115 enum vnic_dev_intr_mode intr_mode); 117 enum vnic_dev_intr_mode intr_mode);
116enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); 118enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
119u32 vnic_dev_intr_coal_timer_usec_to_hw(struct vnic_dev *vdev, u32 usec);
120u32 vnic_dev_intr_coal_timer_hw_to_usec(struct vnic_dev *vdev, u32 hw_cycles);
121u32 vnic_dev_get_intr_coal_timer_max(struct vnic_dev *vdev);
117void vnic_dev_unregister(struct vnic_dev *vdev); 122void vnic_dev_unregister(struct vnic_dev *vdev);
118int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev, 123int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
119 u8 ig_vlan_rewrite_mode); 124 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 {
318 * ERR_EINPROGRESS - command in a0 is still in progress 318 * ERR_EINPROGRESS - command in a0 is still in progress
319 */ 319 */
320 CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49), 320 CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49),
321
322 /*
323 * Returns interrupt coalescing timer conversion factors.
324 * After calling this devcmd, ENIC driver can convert
325 * interrupt coalescing timer in usec into CPU cycles as follows:
326 *
327 * intr_timer_cycles = intr_timer_usec * multiplier / divisor
328 *
329 * Interrupt coalescing timer in usecs can be obtained from
330 * CPU cycles as follows:
331 *
332 * intr_timer_usec = intr_timer_cycles * divisor / multiplier
333 *
334 * in: none
335 * out: (u32)a0 = multiplier
336 * (u32)a1 = divisor
337 * (u32)a2 = maximum timer value in usec
338 */
339 CMD_INTR_COAL_CONVERT = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 50),
321}; 340};
322 341
323/* CMD_ENABLE2 flags */ 342/* 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 @@
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
27/* Device-specific region: enet configuration */ 23/* Device-specific region: enet configuration */
28struct vnic_enet_config { 24struct vnic_enet_config {
29 u32 flags; 25 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,
46 return 0; 46 return 0;
47} 47}
48 48
49void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, 49void vnic_intr_init(struct vnic_intr *intr, u32 coalescing_timer,
50 unsigned int coalescing_type, unsigned int mask_on_assertion) 50 unsigned int coalescing_type, unsigned int mask_on_assertion)
51{ 51{
52 vnic_intr_coalescing_timer_set(intr, coalescing_timer); 52 vnic_intr_coalescing_timer_set(intr, coalescing_timer);
@@ -56,9 +56,10 @@ void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
56} 56}
57 57
58void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, 58void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
59 unsigned int coalescing_timer) 59 u32 coalescing_timer)
60{ 60{
61 iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); 61 iowrite32(vnic_dev_intr_coal_timer_usec_to_hw(intr->vdev,
62 coalescing_timer), &intr->ctrl->coalescing_timer);
62} 63}
63 64
64void vnic_intr_clean(struct vnic_intr *intr) 65void 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 @@
24 24
25#include "vnic_dev.h" 25#include "vnic_dev.h"
26 26
27#define VNIC_INTR_TIMER_MAX 0xffff
28
29#define VNIC_INTR_TIMER_TYPE_ABS 0 27#define VNIC_INTR_TIMER_TYPE_ABS 0
30#define VNIC_INTR_TIMER_TYPE_QUIET 1 28#define VNIC_INTR_TIMER_TYPE_QUIET 1
31 29
@@ -104,10 +102,10 @@ static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
104void vnic_intr_free(struct vnic_intr *intr); 102void vnic_intr_free(struct vnic_intr *intr);
105int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, 103int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
106 unsigned int index); 104 unsigned int index);
107void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, 105void vnic_intr_init(struct vnic_intr *intr, u32 coalescing_timer,
108 unsigned int coalescing_type, unsigned int mask_on_assertion); 106 unsigned int coalescing_type, unsigned int mask_on_assertion);
109void vnic_intr_coalescing_timer_set(struct vnic_intr *intr, 107void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
110 unsigned int coalescing_timer); 108 u32 coalescing_timer);
111void vnic_intr_clean(struct vnic_intr *intr); 109void vnic_intr_clean(struct vnic_intr *intr);
112 110
113#endif /* _VNIC_INTR_H_ */ 111#endif /* _VNIC_INTR_H_ */