aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/cisco
diff options
context:
space:
mode:
authorSujith Sankar <ssujith@cisco.com>2014-05-19 17:44:05 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-21 17:04:13 -0400
commit7c2ce6e60f7036de313a8c516ffe2aea889c738f (patch)
treee0d4a76efddc1bdfaab78149c145aee5d5fed2fb /drivers/net/ethernet/cisco
parentf6e92d10002f584d8ec31c39aea733211bf82c0c (diff)
enic: Add support for adaptive interrupt coalescing
This patch adds support for adaptive interrupt coalescing. For small pkts with low pkt rate, we can decrease the coalescing interrupt dynamically which decreases the latency. This however increases the cpu utilization. Based on testing with different coal intr and pkt rate we came up with a table(mod_table) with rx_rate and coalescing interrupt value where we get low latency without significant increase in cpu. mod_table table stores the coalescing timer percentage value for different throughputs. Function enic_calc_int_moderation() calculates the desired coalescing intr timer value. This function is called in driver rx napi_poll. The actual value is set by enic_set_int_moderation() which is called when napi_poll is complete. i.e when we unmask the rx intr. Adaptive coal intr is support only when driver is using msix intr. Because intr is not shared. Struct mod_range is used to store only the default adaptive coalescing intr value. Adaptive coal intr calue is calculated by timer = range_start + ((rx_coal->range_end - range_start) * mod_table[index].range_percent / 100); rx_coal->range_end is the rx-usecs-high value set using ethtool. range_start is rx-usecs-low, set using ethtool, if rx_small_pkt_bytes_cnt is greater than 2 * rx_large_pkt_bytes_cnt. i.e small pkts are dominant. Else its rx-usecs-low + 3. Cc: Christian Benvenuti <benve@cisco.com> Cc: Neel Patel <neepatel@cisco.com> Signed-off-by: Sujith Sankar <ssujith@cisco.com> Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/cisco')
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h30
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c61
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c150
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_cq.h9
4 files changed, 244 insertions, 6 deletions
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index e35c8e0202ad..f23ef321606c 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -43,6 +43,8 @@
43#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX) 43#define ENIC_CQ_MAX (ENIC_WQ_MAX + ENIC_RQ_MAX)
44#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2) 44#define ENIC_INTR_MAX (ENIC_CQ_MAX + 2)
45 45
46#define ENIC_AIC_LARGE_PKT_DIFF 3
47
46struct enic_msix_entry { 48struct enic_msix_entry {
47 int requested; 49 int requested;
48 char devname[IFNAMSIZ]; 50 char devname[IFNAMSIZ];
@@ -50,6 +52,33 @@ struct enic_msix_entry {
50 void *devid; 52 void *devid;
51}; 53};
52 54
55/* Store only the lower range. Higher range is given by fw. */
56struct enic_intr_mod_range {
57 u32 small_pkt_range_start;
58 u32 large_pkt_range_start;
59};
60
61struct enic_intr_mod_table {
62 u32 rx_rate;
63 u32 range_percent;
64};
65
66#define ENIC_MAX_LINK_SPEEDS 3
67#define ENIC_LINK_SPEED_10G 10000
68#define ENIC_LINK_SPEED_4G 4000
69#define ENIC_LINK_40G_INDEX 2
70#define ENIC_LINK_10G_INDEX 1
71#define ENIC_LINK_4G_INDEX 0
72#define ENIC_RX_COALESCE_RANGE_END 125
73#define ENIC_AIC_TS_BREAK 100
74
75struct enic_rx_coal {
76 u32 small_pkt_range_start;
77 u32 large_pkt_range_start;
78 u32 range_end;
79 u32 use_adaptive_rx_coalesce;
80};
81
53/* priv_flags */ 82/* priv_flags */
54#define ENIC_SRIOV_ENABLED (1 << 0) 83#define ENIC_SRIOV_ENABLED (1 << 0)
55 84
@@ -92,6 +121,7 @@ struct enic {
92 unsigned int mc_count; 121 unsigned int mc_count;
93 unsigned int uc_count; 122 unsigned int uc_count;
94 u32 port_mtu; 123 u32 port_mtu;
124 struct enic_rx_coal rx_coalesce_setting;
95 u32 rx_coalesce_usecs; 125 u32 rx_coalesce_usecs;
96 u32 tx_coalesce_usecs; 126 u32 tx_coalesce_usecs;
97#ifdef CONFIG_PCI_IOV 127#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index 58a8c67638e3..1882db230e13 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -79,6 +79,17 @@ static const struct enic_stat enic_rx_stats[] = {
79static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats); 79static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
80static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats); 80static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
81 81
82void enic_intr_coal_set_rx(struct enic *enic, u32 timer)
83{
84 int i;
85 int intr;
86
87 for (i = 0; i < enic->rq_count; i++) {
88 intr = enic_msix_rq_intr(enic, i);
89 vnic_intr_coalescing_timer_set(&enic->intr[intr], timer);
90 }
91}
92
82static int enic_get_settings(struct net_device *netdev, 93static int enic_get_settings(struct net_device *netdev,
83 struct ethtool_cmd *ecmd) 94 struct ethtool_cmd *ecmd)
84{ 95{
@@ -178,9 +189,14 @@ static int enic_get_coalesce(struct net_device *netdev,
178 struct ethtool_coalesce *ecmd) 189 struct ethtool_coalesce *ecmd)
179{ 190{
180 struct enic *enic = netdev_priv(netdev); 191 struct enic *enic = netdev_priv(netdev);
192 struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;
181 193
182 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; 194 ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
183 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; 195 ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
196 if (rxcoal->use_adaptive_rx_coalesce)
197 ecmd->use_adaptive_rx_coalesce = 1;
198 ecmd->rx_coalesce_usecs_low = rxcoal->small_pkt_range_start;
199 ecmd->rx_coalesce_usecs_high = rxcoal->range_end;
184 200
185 return 0; 201 return 0;
186} 202}
@@ -191,17 +207,31 @@ static int enic_set_coalesce(struct net_device *netdev,
191 struct enic *enic = netdev_priv(netdev); 207 struct enic *enic = netdev_priv(netdev);
192 u32 tx_coalesce_usecs; 208 u32 tx_coalesce_usecs;
193 u32 rx_coalesce_usecs; 209 u32 rx_coalesce_usecs;
210 u32 rx_coalesce_usecs_low;
211 u32 rx_coalesce_usecs_high;
212 u32 coalesce_usecs_max;
194 unsigned int i, intr; 213 unsigned int i, intr;
214 struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting;
195 215
216 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev);
196 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, 217 tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs,
197 vnic_dev_get_intr_coal_timer_max(enic->vdev)); 218 coalesce_usecs_max);
198 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs, 219 rx_coalesce_usecs = min_t(u32, ecmd->rx_coalesce_usecs,
199 vnic_dev_get_intr_coal_timer_max(enic->vdev)); 220 coalesce_usecs_max);
221
222 rx_coalesce_usecs_low = min_t(u32, ecmd->rx_coalesce_usecs_low,
223 coalesce_usecs_max);
224 rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high,
225 coalesce_usecs_max);
200 226
201 switch (vnic_dev_get_intr_mode(enic->vdev)) { 227 switch (vnic_dev_get_intr_mode(enic->vdev)) {
202 case VNIC_DEV_INTR_MODE_INTX: 228 case VNIC_DEV_INTR_MODE_INTX:
203 if (tx_coalesce_usecs != rx_coalesce_usecs) 229 if (tx_coalesce_usecs != rx_coalesce_usecs)
204 return -EINVAL; 230 return -EINVAL;
231 if (ecmd->use_adaptive_rx_coalesce ||
232 ecmd->rx_coalesce_usecs_low ||
233 ecmd->rx_coalesce_usecs_high)
234 return -EOPNOTSUPP;
205 235
206 intr = enic_legacy_io_intr(); 236 intr = enic_legacy_io_intr();
207 vnic_intr_coalescing_timer_set(&enic->intr[intr], 237 vnic_intr_coalescing_timer_set(&enic->intr[intr],
@@ -210,6 +240,10 @@ static int enic_set_coalesce(struct net_device *netdev,
210 case VNIC_DEV_INTR_MODE_MSI: 240 case VNIC_DEV_INTR_MODE_MSI:
211 if (tx_coalesce_usecs != rx_coalesce_usecs) 241 if (tx_coalesce_usecs != rx_coalesce_usecs)
212 return -EINVAL; 242 return -EINVAL;
243 if (ecmd->use_adaptive_rx_coalesce ||
244 ecmd->rx_coalesce_usecs_low ||
245 ecmd->rx_coalesce_usecs_high)
246 return -EOPNOTSUPP;
213 247
214 vnic_intr_coalescing_timer_set(&enic->intr[0], 248 vnic_intr_coalescing_timer_set(&enic->intr[0],
215 tx_coalesce_usecs); 249 tx_coalesce_usecs);
@@ -221,12 +255,27 @@ static int enic_set_coalesce(struct net_device *netdev,
221 tx_coalesce_usecs); 255 tx_coalesce_usecs);
222 } 256 }
223 257
224 for (i = 0; i < enic->rq_count; i++) { 258 if (rxcoal->use_adaptive_rx_coalesce) {
225 intr = enic_msix_rq_intr(enic, i); 259 if (!ecmd->use_adaptive_rx_coalesce) {
226 vnic_intr_coalescing_timer_set(&enic->intr[intr], 260 rxcoal->use_adaptive_rx_coalesce = 0;
227 rx_coalesce_usecs); 261 enic_intr_coal_set_rx(enic, rx_coalesce_usecs);
262 }
263 } else {
264 if (ecmd->use_adaptive_rx_coalesce)
265 rxcoal->use_adaptive_rx_coalesce = 1;
266 else
267 enic_intr_coal_set_rx(enic, rx_coalesce_usecs);
228 } 268 }
229 269
270 if (ecmd->rx_coalesce_usecs_high) {
271 if (rx_coalesce_usecs_high <
272 (rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF))
273 return -EINVAL;
274 rxcoal->range_end = rx_coalesce_usecs_high;
275 rxcoal->small_pkt_range_start = rx_coalesce_usecs_low;
276 rxcoal->large_pkt_range_start = rx_coalesce_usecs_low +
277 ENIC_AIC_LARGE_PKT_DIFF;
278 }
230 break; 279 break;
231 default: 280 default:
232 break; 281 break;
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index 2945718ce806..0d8995cc92ed 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -38,6 +38,7 @@
38#include <linux/rtnetlink.h> 38#include <linux/rtnetlink.h>
39#include <linux/prefetch.h> 39#include <linux/prefetch.h>
40#include <net/ip6_checksum.h> 40#include <net/ip6_checksum.h>
41#include <linux/ktime.h>
41 42
42#include "cq_enet_desc.h" 43#include "cq_enet_desc.h"
43#include "vnic_dev.h" 44#include "vnic_dev.h"
@@ -72,6 +73,35 @@ MODULE_LICENSE("GPL");
72MODULE_VERSION(DRV_VERSION); 73MODULE_VERSION(DRV_VERSION);
73MODULE_DEVICE_TABLE(pci, enic_id_table); 74MODULE_DEVICE_TABLE(pci, enic_id_table);
74 75
76#define ENIC_LARGE_PKT_THRESHOLD 1000
77#define ENIC_MAX_COALESCE_TIMERS 10
78/* Interrupt moderation table, which will be used to decide the
79 * coalescing timer values
80 * {rx_rate in Mbps, mapping percentage of the range}
81 */
82struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = {
83 {4000, 0},
84 {4400, 10},
85 {5060, 20},
86 {5230, 30},
87 {5540, 40},
88 {5820, 50},
89 {6120, 60},
90 {6435, 70},
91 {6745, 80},
92 {7000, 90},
93 {0xFFFFFFFF, 100}
94};
95
96/* This table helps the driver to pick different ranges for rx coalescing
97 * timer depending on the link speed.
98 */
99struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = {
100 {0, 0}, /* 0 - 4 Gbps */
101 {0, 3}, /* 4 - 10 Gbps */
102 {3, 6}, /* 10 - 40 Gbps */
103};
104
75int enic_is_dynamic(struct enic *enic) 105int enic_is_dynamic(struct enic *enic)
76{ 106{
77 return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN; 107 return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
@@ -979,6 +1009,15 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
979 return 0; 1009 return 0;
980} 1010}
981 1011
1012static void enic_intr_update_pkt_size(struct vnic_rx_bytes_counter *pkt_size,
1013 u32 pkt_len)
1014{
1015 if (ENIC_LARGE_PKT_THRESHOLD <= pkt_len)
1016 pkt_size->large_pkt_bytes_cnt += pkt_len;
1017 else
1018 pkt_size->small_pkt_bytes_cnt += pkt_len;
1019}
1020
982static void enic_rq_indicate_buf(struct vnic_rq *rq, 1021static void enic_rq_indicate_buf(struct vnic_rq *rq,
983 struct cq_desc *cq_desc, struct vnic_rq_buf *buf, 1022 struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
984 int skipped, void *opaque) 1023 int skipped, void *opaque)
@@ -986,6 +1025,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
986 struct enic *enic = vnic_dev_priv(rq->vdev); 1025 struct enic *enic = vnic_dev_priv(rq->vdev);
987 struct net_device *netdev = enic->netdev; 1026 struct net_device *netdev = enic->netdev;
988 struct sk_buff *skb; 1027 struct sk_buff *skb;
1028 struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
989 1029
990 u8 type, color, eop, sop, ingress_port, vlan_stripped; 1030 u8 type, color, eop, sop, ingress_port, vlan_stripped;
991 u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; 1031 u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
@@ -1056,6 +1096,9 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
1056 napi_gro_receive(&enic->napi[q_number], skb); 1096 napi_gro_receive(&enic->napi[q_number], skb);
1057 else 1097 else
1058 netif_receive_skb(skb); 1098 netif_receive_skb(skb);
1099 if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
1100 enic_intr_update_pkt_size(&cq->pkt_size_counter,
1101 bytes_written);
1059 } else { 1102 } else {
1060 1103
1061 /* Buffer overflow 1104 /* Buffer overflow
@@ -1134,6 +1177,64 @@ static int enic_poll(struct napi_struct *napi, int budget)
1134 return rq_work_done; 1177 return rq_work_done;
1135} 1178}
1136 1179
1180static void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq)
1181{
1182 unsigned int intr = enic_msix_rq_intr(enic, rq->index);
1183 struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
1184 u32 timer = cq->tobe_rx_coal_timeval;
1185
1186 if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) {
1187 vnic_intr_coalescing_timer_set(&enic->intr[intr], timer);
1188 cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval;
1189 }
1190}
1191
1192static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq)
1193{
1194 struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting;
1195 struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
1196 struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter;
1197 int index;
1198 u32 timer;
1199 u32 range_start;
1200 u32 traffic;
1201 u64 delta;
1202 ktime_t now = ktime_get();
1203
1204 delta = ktime_us_delta(now, cq->prev_ts);
1205 if (delta < ENIC_AIC_TS_BREAK)
1206 return;
1207 cq->prev_ts = now;
1208
1209 traffic = pkt_size_counter->large_pkt_bytes_cnt +
1210 pkt_size_counter->small_pkt_bytes_cnt;
1211 /* The table takes Mbps
1212 * traffic *= 8 => bits
1213 * traffic *= (10^6 / delta) => bps
1214 * traffic /= 10^6 => Mbps
1215 *
1216 * Combining, traffic *= (8 / delta)
1217 */
1218
1219 traffic <<= 3;
1220 traffic /= delta;
1221
1222 for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++)
1223 if (traffic < mod_table[index].rx_rate)
1224 break;
1225 range_start = (pkt_size_counter->small_pkt_bytes_cnt >
1226 pkt_size_counter->large_pkt_bytes_cnt << 1) ?
1227 rx_coal->small_pkt_range_start :
1228 rx_coal->large_pkt_range_start;
1229 timer = range_start + ((rx_coal->range_end - range_start) *
1230 mod_table[index].range_percent / 100);
1231 /* Damping */
1232 cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1;
1233
1234 pkt_size_counter->large_pkt_bytes_cnt = 0;
1235 pkt_size_counter->small_pkt_bytes_cnt = 0;
1236}
1237
1137static int enic_poll_msix(struct napi_struct *napi, int budget) 1238static int enic_poll_msix(struct napi_struct *napi, int budget)
1138{ 1239{
1139 struct net_device *netdev = napi->dev; 1240 struct net_device *netdev = napi->dev;
@@ -1171,6 +1272,13 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
1171 1272
1172 if (err) 1273 if (err)
1173 work_done = work_to_do; 1274 work_done = work_to_do;
1275 if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
1276 /* Call the function which refreshes
1277 * the intr coalescing timer value based on
1278 * the traffic. This is supported only in
1279 * the case of MSI-x mode
1280 */
1281 enic_calc_int_moderation(enic, &enic->rq[rq]);
1174 1282
1175 if (work_done < work_to_do) { 1283 if (work_done < work_to_do) {
1176 1284
@@ -1179,6 +1287,8 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
1179 */ 1287 */
1180 1288
1181 napi_complete(napi); 1289 napi_complete(napi);
1290 if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
1291 enic_set_int_moderation(enic, &enic->rq[rq]);
1182 vnic_intr_unmask(&enic->intr[intr]); 1292 vnic_intr_unmask(&enic->intr[intr]);
1183 } 1293 }
1184 1294
@@ -1314,6 +1424,42 @@ static void enic_synchronize_irqs(struct enic *enic)
1314 } 1424 }
1315} 1425}
1316 1426
1427static void enic_set_rx_coal_setting(struct enic *enic)
1428{
1429 unsigned int speed;
1430 int index = -1;
1431 struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting;
1432
1433 /* If intr mode is not MSIX, do not do adaptive coalescing */
1434 if (VNIC_DEV_INTR_MODE_MSIX != vnic_dev_get_intr_mode(enic->vdev)) {
1435 netdev_info(enic->netdev, "INTR mode is not MSIX, Not initializing adaptive coalescing");
1436 return;
1437 }
1438
1439 /* 1. Read the link speed from fw
1440 * 2. Pick the default range for the speed
1441 * 3. Update it in enic->rx_coalesce_setting
1442 */
1443 speed = vnic_dev_port_speed(enic->vdev);
1444 if (ENIC_LINK_SPEED_10G < speed)
1445 index = ENIC_LINK_40G_INDEX;
1446 else if (ENIC_LINK_SPEED_4G < speed)
1447 index = ENIC_LINK_10G_INDEX;
1448 else
1449 index = ENIC_LINK_4G_INDEX;
1450
1451 rx_coal->small_pkt_range_start = mod_range[index].small_pkt_range_start;
1452 rx_coal->large_pkt_range_start = mod_range[index].large_pkt_range_start;
1453 rx_coal->range_end = ENIC_RX_COALESCE_RANGE_END;
1454
1455 /* Start with the value provided by UCSM */
1456 for (index = 0; index < enic->rq_count; index++)
1457 enic->cq[index].cur_rx_coal_timeval =
1458 enic->config.intr_timer_usec;
1459
1460 rx_coal->use_adaptive_rx_coalesce = 1;
1461}
1462
1317static int enic_dev_notify_set(struct enic *enic) 1463static int enic_dev_notify_set(struct enic *enic)
1318{ 1464{
1319 int err; 1465 int err;
@@ -2231,6 +2377,7 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2231 enic->notify_timer.function = enic_notify_timer; 2377 enic->notify_timer.function = enic_notify_timer;
2232 enic->notify_timer.data = (unsigned long)enic; 2378 enic->notify_timer.data = (unsigned long)enic;
2233 2379
2380 enic_set_rx_coal_setting(enic);
2234 INIT_WORK(&enic->reset, enic_reset); 2381 INIT_WORK(&enic->reset, enic_reset);
2235 INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work); 2382 INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
2236 2383
@@ -2250,6 +2397,9 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2250 } 2397 }
2251 2398
2252 enic->tx_coalesce_usecs = enic->config.intr_timer_usec; 2399 enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
2400 /* rx coalesce time already got initialized. This gets used
2401 * if adaptive coal is turned off
2402 */
2253 enic->rx_coalesce_usecs = enic->tx_coalesce_usecs; 2403 enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
2254 2404
2255 if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) 2405 if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic))
diff --git a/drivers/net/ethernet/cisco/enic/vnic_cq.h b/drivers/net/ethernet/cisco/enic/vnic_cq.h
index 579315cbe803..4e6aa65857f7 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_cq.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_cq.h
@@ -50,6 +50,11 @@ struct vnic_cq_ctrl {
50 u32 pad10; 50 u32 pad10;
51}; 51};
52 52
53struct vnic_rx_bytes_counter {
54 unsigned int small_pkt_bytes_cnt;
55 unsigned int large_pkt_bytes_cnt;
56};
57
53struct vnic_cq { 58struct vnic_cq {
54 unsigned int index; 59 unsigned int index;
55 struct vnic_dev *vdev; 60 struct vnic_dev *vdev;
@@ -58,6 +63,10 @@ struct vnic_cq {
58 unsigned int to_clean; 63 unsigned int to_clean;
59 unsigned int last_color; 64 unsigned int last_color;
60 unsigned int interrupt_offset; 65 unsigned int interrupt_offset;
66 struct vnic_rx_bytes_counter pkt_size_counter;
67 unsigned int cur_rx_coal_timeval;
68 unsigned int tobe_rx_coal_timeval;
69 ktime_t prev_ts;
61}; 70};
62 71
63static inline unsigned int vnic_cq_service(struct vnic_cq *cq, 72static inline unsigned int vnic_cq_service(struct vnic_cq *cq,