aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/emulex/benet
diff options
context:
space:
mode:
authorSathya Perla <sathya.perla@emulex.com>2013-10-01 06:30:00 -0400
committerDavid S. Miller <davem@davemloft.net>2013-10-01 12:45:52 -0400
commit2632bafd74ae7d058ae52be80e6393139fd29f23 (patch)
treea1119a741b44afc7e68ab02b320a306c2238df30 /drivers/net/ethernet/emulex/benet
parent0599863d35410ea65ceadcca87497985b371039a (diff)
be2net: fix adaptive interrupt coalescing
The current EQ delay calculation for AIC is based only on RX packet rate. This fails to be effective when there's only TX and no RX. This patch inclues: - Calculating EQ-delay based on both RX and TX pps. - Modifying EQ-delay of all EQs via one cmd, instead of issuing a separate cmd for each EQ. - A new structure to store interrupt coalescing parameters, in a separate cache-line from the EQ-obj. Signed-off-by: Sathya Perla <sathya.perla@emulex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/emulex/benet')
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h17
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c17
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h15
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c29
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c110
5 files changed, 115 insertions, 73 deletions
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 4a540aff698c..e7cbc56a0c8f 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -88,7 +88,7 @@ static inline char *nic_name(struct pci_dev *pdev)
88#define BE_MIN_MTU 256 88#define BE_MIN_MTU 256
89 89
90#define BE_NUM_VLANS_SUPPORTED 64 90#define BE_NUM_VLANS_SUPPORTED 64
91#define BE_MAX_EQD 96u 91#define BE_MAX_EQD 128u
92#define BE_MAX_TX_FRAG_COUNT 30 92#define BE_MAX_TX_FRAG_COUNT 30
93 93
94#define EVNT_Q_LEN 1024 94#define EVNT_Q_LEN 1024
@@ -200,6 +200,17 @@ struct be_eq_obj {
200 struct be_adapter *adapter; 200 struct be_adapter *adapter;
201} ____cacheline_aligned_in_smp; 201} ____cacheline_aligned_in_smp;
202 202
203struct be_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
204 bool enable;
205 u32 min_eqd; /* in usecs */
206 u32 max_eqd; /* in usecs */
207 u32 prev_eqd; /* in usecs */
208 u32 et_eqd; /* configured val when aic is off */
209 ulong jiffies;
210 u64 rx_pkts_prev; /* Used to calculate RX pps */
211 u64 tx_reqs_prev; /* Used to calculate TX pps */
212};
213
203struct be_mcc_obj { 214struct be_mcc_obj {
204 struct be_queue_info q; 215 struct be_queue_info q;
205 struct be_queue_info cq; 216 struct be_queue_info cq;
@@ -238,15 +249,12 @@ struct be_rx_page_info {
238struct be_rx_stats { 249struct be_rx_stats {
239 u64 rx_bytes; 250 u64 rx_bytes;
240 u64 rx_pkts; 251 u64 rx_pkts;
241 u64 rx_pkts_prev;
242 ulong rx_jiffies;
243 u32 rx_drops_no_skbs; /* skb allocation errors */ 252 u32 rx_drops_no_skbs; /* skb allocation errors */
244 u32 rx_drops_no_frags; /* HW has no fetched frags */ 253 u32 rx_drops_no_frags; /* HW has no fetched frags */
245 u32 rx_post_fail; /* page post alloc failures */ 254 u32 rx_post_fail; /* page post alloc failures */
246 u32 rx_compl; 255 u32 rx_compl;
247 u32 rx_mcast_pkts; 256 u32 rx_mcast_pkts;
248 u32 rx_compl_err; /* completions with err set */ 257 u32 rx_compl_err; /* completions with err set */
249 u32 rx_pps; /* pkts per second */
250 struct u64_stats_sync sync; 258 struct u64_stats_sync sync;
251}; 259};
252 260
@@ -403,6 +411,7 @@ struct be_adapter {
403 u32 big_page_size; /* Compounded page size shared by rx wrbs */ 411 u32 big_page_size; /* Compounded page size shared by rx wrbs */
404 412
405 struct be_drv_stats drv_stats; 413 struct be_drv_stats drv_stats;
414 struct be_aic_obj aic_obj[MAX_EVT_QS];
406 u16 vlans_added; 415 u16 vlans_added;
407 u8 vlan_tag[VLAN_N_VID]; 416 u8 vlan_tag[VLAN_N_VID];
408 u8 vlan_prio_bmap; /* Available Priority BitMap */ 417 u8 vlan_prio_bmap; /* Available Priority BitMap */
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 86105305d552..b28248770d85 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -1716,11 +1716,12 @@ err:
1716/* set the EQ delay interval of an EQ to specified value 1716/* set the EQ delay interval of an EQ to specified value
1717 * Uses async mcc 1717 * Uses async mcc
1718 */ 1718 */
1719int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) 1719int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *set_eqd,
1720 int num)
1720{ 1721{
1721 struct be_mcc_wrb *wrb; 1722 struct be_mcc_wrb *wrb;
1722 struct be_cmd_req_modify_eq_delay *req; 1723 struct be_cmd_req_modify_eq_delay *req;
1723 int status = 0; 1724 int status = 0, i;
1724 1725
1725 spin_lock_bh(&adapter->mcc_lock); 1726 spin_lock_bh(&adapter->mcc_lock);
1726 1727
@@ -1734,13 +1735,15 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd)
1734 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, 1735 be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
1735 OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req), wrb, NULL); 1736 OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req), wrb, NULL);
1736 1737
1737 req->num_eq = cpu_to_le32(1); 1738 req->num_eq = cpu_to_le32(num);
1738 req->delay[0].eq_id = cpu_to_le32(eq_id); 1739 for (i = 0; i < num; i++) {
1739 req->delay[0].phase = 0; 1740 req->set_eqd[i].eq_id = cpu_to_le32(set_eqd[i].eq_id);
1740 req->delay[0].delay_multiplier = cpu_to_le32(eqd); 1741 req->set_eqd[i].phase = 0;
1742 req->set_eqd[i].delay_multiplier =
1743 cpu_to_le32(set_eqd[i].delay_multiplier);
1744 }
1741 1745
1742 be_mcc_notify(adapter); 1746 be_mcc_notify(adapter);
1743
1744err: 1747err:
1745 spin_unlock_bh(&adapter->mcc_lock); 1748 spin_unlock_bh(&adapter->mcc_lock);
1746 return status; 1749 return status;
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 84f8c5243655..70c3017288d5 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1055,14 +1055,16 @@ struct be_cmd_resp_get_flow_control {
1055} __packed; 1055} __packed;
1056 1056
1057/******************** Modify EQ Delay *******************/ 1057/******************** Modify EQ Delay *******************/
1058struct be_set_eqd {
1059 u32 eq_id;
1060 u32 phase;
1061 u32 delay_multiplier;
1062};
1063
1058struct be_cmd_req_modify_eq_delay { 1064struct be_cmd_req_modify_eq_delay {
1059 struct be_cmd_req_hdr hdr; 1065 struct be_cmd_req_hdr hdr;
1060 u32 num_eq; 1066 u32 num_eq;
1061 struct { 1067 struct be_set_eqd set_eqd[MAX_EVT_QS];
1062 u32 eq_id;
1063 u32 phase;
1064 u32 delay_multiplier;
1065 } delay[8];
1066} __packed; 1068} __packed;
1067 1069
1068struct be_cmd_resp_modify_eq_delay { 1070struct be_cmd_resp_modify_eq_delay {
@@ -1894,8 +1896,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
1894 struct be_dma_mem *nonemb_cmd); 1896 struct be_dma_mem *nonemb_cmd);
1895int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver, 1897int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver,
1896 char *fw_on_flash); 1898 char *fw_on_flash);
1897 1899int be_cmd_modify_eqd(struct be_adapter *adapter, struct be_set_eqd *, int num);
1898int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd);
1899int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, 1900int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array,
1900 u32 num, bool untagged, bool promiscuous); 1901 u32 num, bool untagged, bool promiscuous);
1901int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status); 1902int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 status);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index b440a1fac77b..a08783c7456e 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -290,19 +290,19 @@ static int be_get_coalesce(struct net_device *netdev,
290 struct ethtool_coalesce *et) 290 struct ethtool_coalesce *et)
291{ 291{
292 struct be_adapter *adapter = netdev_priv(netdev); 292 struct be_adapter *adapter = netdev_priv(netdev);
293 struct be_eq_obj *eqo = &adapter->eq_obj[0]; 293 struct be_aic_obj *aic = &adapter->aic_obj[0];
294 294
295 295
296 et->rx_coalesce_usecs = eqo->cur_eqd; 296 et->rx_coalesce_usecs = aic->prev_eqd;
297 et->rx_coalesce_usecs_high = eqo->max_eqd; 297 et->rx_coalesce_usecs_high = aic->max_eqd;
298 et->rx_coalesce_usecs_low = eqo->min_eqd; 298 et->rx_coalesce_usecs_low = aic->min_eqd;
299 299
300 et->tx_coalesce_usecs = eqo->cur_eqd; 300 et->tx_coalesce_usecs = aic->prev_eqd;
301 et->tx_coalesce_usecs_high = eqo->max_eqd; 301 et->tx_coalesce_usecs_high = aic->max_eqd;
302 et->tx_coalesce_usecs_low = eqo->min_eqd; 302 et->tx_coalesce_usecs_low = aic->min_eqd;
303 303
304 et->use_adaptive_rx_coalesce = eqo->enable_aic; 304 et->use_adaptive_rx_coalesce = aic->enable;
305 et->use_adaptive_tx_coalesce = eqo->enable_aic; 305 et->use_adaptive_tx_coalesce = aic->enable;
306 306
307 return 0; 307 return 0;
308} 308}
@@ -314,14 +314,17 @@ static int be_set_coalesce(struct net_device *netdev,
314 struct ethtool_coalesce *et) 314 struct ethtool_coalesce *et)
315{ 315{
316 struct be_adapter *adapter = netdev_priv(netdev); 316 struct be_adapter *adapter = netdev_priv(netdev);
317 struct be_aic_obj *aic = &adapter->aic_obj[0];
317 struct be_eq_obj *eqo; 318 struct be_eq_obj *eqo;
318 int i; 319 int i;
319 320
320 for_all_evt_queues(adapter, eqo, i) { 321 for_all_evt_queues(adapter, eqo, i) {
321 eqo->enable_aic = et->use_adaptive_rx_coalesce; 322 aic->enable = et->use_adaptive_rx_coalesce;
322 eqo->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD); 323 aic->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD);
323 eqo->min_eqd = min(et->rx_coalesce_usecs_low, eqo->max_eqd); 324 aic->min_eqd = min(et->rx_coalesce_usecs_low, aic->max_eqd);
324 eqo->eqd = et->rx_coalesce_usecs; 325 aic->et_eqd = min(et->rx_coalesce_usecs, aic->max_eqd);
326 aic->et_eqd = max(aic->et_eqd, aic->min_eqd);
327 aic++;
325 } 328 }
326 329
327 return 0; 330 return 0;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 961e9f0500c5..6691d75b6cca 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1261,53 +1261,79 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
1261 return status; 1261 return status;
1262} 1262}
1263 1263
1264static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo) 1264static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
1265 ulong now)
1265{ 1266{
1266 struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]); 1267 aic->rx_pkts_prev = rx_pkts;
1267 ulong now = jiffies; 1268 aic->tx_reqs_prev = tx_pkts;
1268 ulong delta = now - stats->rx_jiffies; 1269 aic->jiffies = now;
1269 u64 pkts; 1270}
1270 unsigned int start, eqd;
1271 1271
1272 if (!eqo->enable_aic) { 1272static void be_eqd_update(struct be_adapter *adapter)
1273 eqd = eqo->eqd; 1273{
1274 goto modify_eqd; 1274 struct be_set_eqd set_eqd[MAX_EVT_QS];
1275 } 1275 int eqd, i, num = 0, start;
1276 struct be_aic_obj *aic;
1277 struct be_eq_obj *eqo;
1278 struct be_rx_obj *rxo;
1279 struct be_tx_obj *txo;
1280 u64 rx_pkts, tx_pkts;
1281 ulong now;
1282 u32 pps, delta;
1276 1283
1277 if (eqo->idx >= adapter->num_rx_qs) 1284 for_all_evt_queues(adapter, eqo, i) {
1278 return; 1285 aic = &adapter->aic_obj[eqo->idx];
1286 if (!aic->enable) {
1287 if (aic->jiffies)
1288 aic->jiffies = 0;
1289 eqd = aic->et_eqd;
1290 goto modify_eqd;
1291 }
1279 1292
1280 stats = rx_stats(&adapter->rx_obj[eqo->idx]); 1293 rxo = &adapter->rx_obj[eqo->idx];
1294 do {
1295 start = u64_stats_fetch_begin_bh(&rxo->stats.sync);
1296 rx_pkts = rxo->stats.rx_pkts;
1297 } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start));
1281 1298
1282 /* Wrapped around */ 1299 txo = &adapter->tx_obj[eqo->idx];
1283 if (time_before(now, stats->rx_jiffies)) { 1300 do {
1284 stats->rx_jiffies = now; 1301 start = u64_stats_fetch_begin_bh(&txo->stats.sync);
1285 return; 1302 tx_pkts = txo->stats.tx_reqs;
1286 } 1303 } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start));
1287 1304
1288 /* Update once a second */
1289 if (delta < HZ)
1290 return;
1291 1305
1292 do { 1306 /* Skip, if wrapped around or first calculation */
1293 start = u64_stats_fetch_begin_bh(&stats->sync); 1307 now = jiffies;
1294 pkts = stats->rx_pkts; 1308 if (!aic->jiffies || time_before(now, aic->jiffies) ||
1295 } while (u64_stats_fetch_retry_bh(&stats->sync, start)); 1309 rx_pkts < aic->rx_pkts_prev ||
1296 1310 tx_pkts < aic->tx_reqs_prev) {
1297 stats->rx_pps = (unsigned long)(pkts - stats->rx_pkts_prev) / (delta / HZ); 1311 be_aic_update(aic, rx_pkts, tx_pkts, now);
1298 stats->rx_pkts_prev = pkts; 1312 continue;
1299 stats->rx_jiffies = now; 1313 }
1300 eqd = (stats->rx_pps / 110000) << 3; 1314
1301 eqd = min(eqd, eqo->max_eqd); 1315 delta = jiffies_to_msecs(now - aic->jiffies);
1302 eqd = max(eqd, eqo->min_eqd); 1316 pps = (((u32)(rx_pkts - aic->rx_pkts_prev) * 1000) / delta) +
1303 if (eqd < 10) 1317 (((u32)(tx_pkts - aic->tx_reqs_prev) * 1000) / delta);
1304 eqd = 0; 1318 eqd = (pps / 15000) << 2;
1305 1319
1320 if (eqd < 8)
1321 eqd = 0;
1322 eqd = min_t(u32, eqd, aic->max_eqd);
1323 eqd = max_t(u32, eqd, aic->min_eqd);
1324
1325 be_aic_update(aic, rx_pkts, tx_pkts, now);
1306modify_eqd: 1326modify_eqd:
1307 if (eqd != eqo->cur_eqd) { 1327 if (eqd != aic->prev_eqd) {
1308 be_cmd_modify_eqd(adapter, eqo->q.id, eqd); 1328 set_eqd[num].delay_multiplier = (eqd * 65)/100;
1309 eqo->cur_eqd = eqd; 1329 set_eqd[num].eq_id = eqo->q.id;
1330 aic->prev_eqd = eqd;
1331 num++;
1332 }
1310 } 1333 }
1334
1335 if (num)
1336 be_cmd_modify_eqd(adapter, set_eqd, num);
1311} 1337}
1312 1338
1313static void be_rx_stats_update(struct be_rx_obj *rxo, 1339static void be_rx_stats_update(struct be_rx_obj *rxo,
@@ -1924,6 +1950,7 @@ static int be_evt_queues_create(struct be_adapter *adapter)
1924{ 1950{
1925 struct be_queue_info *eq; 1951 struct be_queue_info *eq;
1926 struct be_eq_obj *eqo; 1952 struct be_eq_obj *eqo;
1953 struct be_aic_obj *aic;
1927 int i, rc; 1954 int i, rc;
1928 1955
1929 adapter->num_evt_qs = min_t(u16, num_irqs(adapter), 1956 adapter->num_evt_qs = min_t(u16, num_irqs(adapter),
@@ -1932,11 +1959,12 @@ static int be_evt_queues_create(struct be_adapter *adapter)
1932 for_all_evt_queues(adapter, eqo, i) { 1959 for_all_evt_queues(adapter, eqo, i) {
1933 netif_napi_add(adapter->netdev, &eqo->napi, be_poll, 1960 netif_napi_add(adapter->netdev, &eqo->napi, be_poll,
1934 BE_NAPI_WEIGHT); 1961 BE_NAPI_WEIGHT);
1962 aic = &adapter->aic_obj[i];
1935 eqo->adapter = adapter; 1963 eqo->adapter = adapter;
1936 eqo->tx_budget = BE_TX_BUDGET; 1964 eqo->tx_budget = BE_TX_BUDGET;
1937 eqo->idx = i; 1965 eqo->idx = i;
1938 eqo->max_eqd = BE_MAX_EQD; 1966 aic->max_eqd = BE_MAX_EQD;
1939 eqo->enable_aic = true; 1967 aic->enable = true;
1940 1968
1941 eq = &eqo->q; 1969 eq = &eqo->q;
1942 rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, 1970 rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
@@ -4240,7 +4268,6 @@ static void be_worker(struct work_struct *work)
4240 struct be_adapter *adapter = 4268 struct be_adapter *adapter =
4241 container_of(work, struct be_adapter, work.work); 4269 container_of(work, struct be_adapter, work.work);
4242 struct be_rx_obj *rxo; 4270 struct be_rx_obj *rxo;
4243 struct be_eq_obj *eqo;
4244 int i; 4271 int i;
4245 4272
4246 /* when interrupts are not yet enabled, just reap any pending 4273 /* when interrupts are not yet enabled, just reap any pending
@@ -4271,8 +4298,7 @@ static void be_worker(struct work_struct *work)
4271 } 4298 }
4272 } 4299 }
4273 4300
4274 for_all_evt_queues(adapter, eqo, i) 4301 be_eqd_update(adapter);
4275 be_eqd_update(adapter, eqo);
4276 4302
4277reschedule: 4303reschedule:
4278 adapter->work_counter++; 4304 adapter->work_counter++;