aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnjali Singhai Jain <anjali.singhai@intel.com>2014-02-12 01:33:25 -0500
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2014-03-14 19:30:03 -0400
commit55a5e60b9f583f64a6c95cfe869dd2d65ae53a95 (patch)
tree769c369562564b3593c53c03b04de071cf9764d5
parent61dade7e9201162cba683cff103cebbdf06655d4 (diff)
i40e: Add code to handle FD table full condition
Add code to enforce the following policy: - If the HW reports filter programming error, we check if it's due to a full table. - If so, we go ahead and turn off new rule addition for ATR and then SB in that order. - We monitor the programmed filter count, if enough room is created due to filter deletion/reset, we then re-enable SB and ATR new rule addition. Change-ID: I69d24b29e5c45bc4fa861258e11c2fa7b8868748 Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com> Signed-off-by: Catherine Sullivan <catherine.sullivan@intel.com> Tested-by: Kavindya Deegala <kavindya.s.deegala@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h7
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c17
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c58
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c60
5 files changed, 135 insertions, 17 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index a19165395b7f..bd1b4690a608 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -152,7 +152,10 @@ struct i40e_lump_tracking {
152}; 152};
153 153
154#define I40E_DEFAULT_ATR_SAMPLE_RATE 20 154#define I40E_DEFAULT_ATR_SAMPLE_RATE 20
155#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 155#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512
156#define I40E_FDIR_BUFFER_FULL_MARGIN 10
157#define I40E_FDIR_BUFFER_HEAD_ROOM 200
158
156struct i40e_fdir_filter { 159struct i40e_fdir_filter {
157 struct hlist_node fdir_node; 160 struct hlist_node fdir_node;
158 /* filter ipnut set */ 161 /* filter ipnut set */
@@ -553,6 +556,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
553 struct i40e_pf *pf, bool add); 556 struct i40e_pf *pf, bool add);
554int i40e_add_del_fdir(struct i40e_vsi *vsi, 557int i40e_add_del_fdir(struct i40e_vsi *vsi,
555 struct i40e_fdir_filter *input, bool add); 558 struct i40e_fdir_filter *input, bool add);
559void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
560int i40e_get_current_fd_count(struct i40e_pf *pf);
556void i40e_set_ethtool_ops(struct net_device *netdev); 561void i40e_set_ethtool_ops(struct net_device *netdev);
557struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, 562struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
558 u8 *macaddr, s16 vlan, 563 u8 *macaddr, s16 vlan,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index 47b9754d1e8e..afd43d7973fa 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1011,10 +1011,12 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
1011 **/ 1011 **/
1012static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable) 1012static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable)
1013{ 1013{
1014 if (enable) 1014 if (enable) {
1015 pf->flags |= flag; 1015 pf->flags |= flag;
1016 else 1016 } else {
1017 pf->flags &= ~flag; 1017 pf->flags &= ~flag;
1018 pf->auto_disable_flags |= flag;
1019 }
1018 dev_info(&pf->pdev->dev, "requesting a pf reset\n"); 1020 dev_info(&pf->pdev->dev, "requesting a pf reset\n");
1019 i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); 1021 i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
1020} 1022}
@@ -1670,6 +1672,15 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
1670 bool add = false; 1672 bool add = false;
1671 int ret; 1673 int ret;
1672 1674
1675 if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
1676 goto command_write_done;
1677
1678 if (strncmp(cmd_buf, "add", 3) == 0)
1679 add = true;
1680
1681 if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
1682 goto command_write_done;
1683
1673 asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, 1684 asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
1674 GFP_KERNEL); 1685 GFP_KERNEL);
1675 if (!asc_packet) 1686 if (!asc_packet)
@@ -1684,8 +1695,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
1684 goto command_write_done; 1695 goto command_write_done;
1685 } 1696 }
1686 1697
1687 if (strncmp(cmd_buf, "add", 3) == 0)
1688 add = true;
1689 cnt = sscanf(&cmd_buf[13], 1698 cnt = sscanf(&cmd_buf[13],
1690 "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s", 1699 "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s",
1691 &fd_data.q_index, 1700 &fd_data.q_index,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 718a3e0f7de4..8ee224fdc1d1 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -1460,6 +1460,7 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
1460 1460
1461 ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd); 1461 ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
1462 1462
1463 i40e_fdir_check_and_reenable(pf);
1463 return ret; 1464 return ret;
1464} 1465}
1465 1466
@@ -1483,9 +1484,16 @@ static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
1483 if (!vsi) 1484 if (!vsi)
1484 return -EINVAL; 1485 return -EINVAL;
1485 1486
1486 fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
1487 pf = vsi->back; 1487 pf = vsi->back;
1488 1488
1489 if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
1490 return -EOPNOTSUPP;
1491
1492 if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
1493 return -ENOSPC;
1494
1495 fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
1496
1489 if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort + 1497 if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
1490 pf->hw.func_caps.fd_filters_guaranteed)) { 1498 pf->hw.func_caps.fd_filters_guaranteed)) {
1491 return -EINVAL; 1499 return -EINVAL;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 63776ea5092c..6185856689bc 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -2436,6 +2436,9 @@ static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
2436 struct i40e_pf *pf = vsi->back; 2436 struct i40e_pf *pf = vsi->back;
2437 struct hlist_node *node; 2437 struct hlist_node *node;
2438 2438
2439 if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
2440 return;
2441
2439 hlist_for_each_entry_safe(filter, node, 2442 hlist_for_each_entry_safe(filter, node,
2440 &pf->fdir_filter_list, fdir_node) { 2443 &pf->fdir_filter_list, fdir_node) {
2441 i40e_add_del_fdir(vsi, filter, true); 2444 i40e_add_del_fdir(vsi, filter, true);
@@ -4624,6 +4627,54 @@ static void i40e_service_event_complete(struct i40e_pf *pf)
4624} 4627}
4625 4628
4626/** 4629/**
4630 * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW
4631 * @pf: board private structure
4632 **/
4633int i40e_get_current_fd_count(struct i40e_pf *pf)
4634{
4635 int val, fcnt_prog;
4636 val = rd32(&pf->hw, I40E_PFQF_FDSTAT);
4637 fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) +
4638 ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
4639 I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
4640 return fcnt_prog;
4641}
4642
4643/**
4644 * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
4645 * @pf: board private structure
4646 **/
4647void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
4648{
4649 u32 fcnt_prog, fcnt_avail;
4650
4651 /* Check if, FD SB or ATR was auto disabled and if there is enough room
4652 * to re-enable
4653 */
4654 if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
4655 (pf->flags & I40E_FLAG_FD_SB_ENABLED))
4656 return;
4657 fcnt_prog = i40e_get_current_fd_count(pf);
4658 fcnt_avail = pf->hw.fdir_shared_filter_count +
4659 pf->fdir_pf_filter_count;
4660 if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
4661 if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
4662 (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
4663 pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
4664 dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
4665 }
4666 }
4667 /* Wait for some more space to be available to turn on ATR */
4668 if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
4669 if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
4670 (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
4671 pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
4672 dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
4673 }
4674 }
4675}
4676
4677/**
4627 * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table 4678 * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
4628 * @pf: board private structure 4679 * @pf: board private structure
4629 **/ 4680 **/
@@ -4632,11 +4683,14 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
4632 if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT)) 4683 if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
4633 return; 4684 return;
4634 4685
4635 pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
4636
4637 /* if interface is down do nothing */ 4686 /* if interface is down do nothing */
4638 if (test_bit(__I40E_DOWN, &pf->state)) 4687 if (test_bit(__I40E_DOWN, &pf->state))
4639 return; 4688 return;
4689 i40e_fdir_check_and_reenable(pf);
4690
4691 if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
4692 (pf->flags & I40E_FLAG_FD_SB_ENABLED))
4693 pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
4640} 4694}
4641 4695
4642/** 4696/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 2081bdb214e5..daa3b295ff3d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -430,23 +430,61 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
430/** 430/**
431 * i40e_fd_handle_status - check the Programming Status for FD 431 * i40e_fd_handle_status - check the Programming Status for FD
432 * @rx_ring: the Rx ring for this descriptor 432 * @rx_ring: the Rx ring for this descriptor
433 * @qw: the descriptor data 433 * @rx_desc: the Rx descriptor for programming Status, not a packet descriptor.
434 * @prog_id: the id originally used for programming 434 * @prog_id: the id originally used for programming
435 * 435 *
436 * This is used to verify if the FD programming or invalidation 436 * This is used to verify if the FD programming or invalidation
437 * requested by SW to the HW is successful or not and take actions accordingly. 437 * requested by SW to the HW is successful or not and take actions accordingly.
438 **/ 438 **/
439static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id) 439static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
440 union i40e_rx_desc *rx_desc, u8 prog_id)
440{ 441{
441 struct pci_dev *pdev = rx_ring->vsi->back->pdev; 442 struct i40e_pf *pf = rx_ring->vsi->back;
443 struct pci_dev *pdev = pf->pdev;
444 u32 fcnt_prog, fcnt_avail;
442 u32 error; 445 u32 error;
446 u64 qw;
443 447
448 qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
444 error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> 449 error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
445 I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; 450 I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
446 451
447 /* for now just print the Status */ 452 if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
448 dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n", 453 dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
449 prog_id, error); 454 rx_desc->wb.qword0.hi_dword.fd_id);
455
456 /* filter programming failed most likely due to table full */
457 fcnt_prog = i40e_get_current_fd_count(pf);
458 fcnt_avail = pf->hw.fdir_shared_filter_count +
459 pf->fdir_pf_filter_count;
460
461 /* If ATR is running fcnt_prog can quickly change,
462 * if we are very close to full, it makes sense to disable
463 * FD ATR/SB and then re-enable it when there is room.
464 */
465 if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
466 /* Turn off ATR first */
467 if (pf->flags | I40E_FLAG_FD_ATR_ENABLED) {
468 pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
469 dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n");
470 pf->auto_disable_flags |=
471 I40E_FLAG_FD_ATR_ENABLED;
472 pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
473 } else if (pf->flags | I40E_FLAG_FD_SB_ENABLED) {
474 pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
475 dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
476 pf->auto_disable_flags |=
477 I40E_FLAG_FD_SB_ENABLED;
478 pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
479 }
480 } else {
481 dev_info(&pdev->dev, "FD filter programming error");
482 }
483 } else if (error ==
484 (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
485 netdev_info(rx_ring->vsi->netdev, "ntuple filter loc = %d, could not be removed\n",
486 rx_desc->wb.qword0.hi_dword.fd_id);
487 }
450} 488}
451 489
452/** 490/**
@@ -843,7 +881,7 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
843 I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT; 881 I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
844 882
845 if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS) 883 if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
846 i40e_fd_handle_status(rx_ring, qw, id); 884 i40e_fd_handle_status(rx_ring, rx_desc, id);
847} 885}
848 886
849/** 887/**
@@ -1536,8 +1574,6 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
1536 if (!tx_ring->atr_sample_rate) 1574 if (!tx_ring->atr_sample_rate)
1537 return; 1575 return;
1538 1576
1539 tx_ring->atr_count++;
1540
1541 /* snag network header to get L4 type and address */ 1577 /* snag network header to get L4 type and address */
1542 hdr.network = skb_network_header(skb); 1578 hdr.network = skb_network_header(skb);
1543 1579
@@ -1559,6 +1595,12 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
1559 1595
1560 th = (struct tcphdr *)(hdr.network + hlen); 1596 th = (struct tcphdr *)(hdr.network + hlen);
1561 1597
1598 /* Due to lack of space, no more new filters can be programmed */
1599 if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
1600 return;
1601
1602 tx_ring->atr_count++;
1603
1562 /* sample on all syn/fin packets or once every atr sample rate */ 1604 /* sample on all syn/fin packets or once every atr sample rate */
1563 if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate)) 1605 if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate))
1564 return; 1606 return;