diff mbox series

igb: add rx drop enable attribute

Message ID 20190828173912.29293-1-bob.beckett@collabora.com
State Superseded
Delegated to: Jeff Kirsher
Headers show
Series igb: add rx drop enable attribute | expand

Commit Message

Robert Beckett Aug. 28, 2019, 5:38 p.m. UTC
To allow userland to enable or disable dropping packets when descriptor
ring is exhausted, add an adapter rx_drop_en attribute.

This can be used in conjunction with flow control to mitigate packet storms
(e.g. due to network loop or DoS) by forcing the network adapter to send
pause frames whenever the ring is close to exhaustion.

By default this will maintain previous behaviour of enabling dropping of
packets during ring buffer exhaustion.
Some use cases prefer to not drop packets upon exhaustion, but instead
use flow control to limit ingress rates and ensure no dropped packets.
This is useful when the host CPU cannot keep up with packet delivery,
but data delivery is more important than throughput via multiple queues.

Userland can write 0 to rx_drop_en to disable packet dropping via udev.

Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
---
 drivers/net/ethernet/intel/igb/igb.h      |  1 +
 drivers/net/ethernet/intel/igb/igb_main.c | 60 ++++++++++++++++++++++-
 2 files changed, 60 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index ca54e268d157..efada57a05e1 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -594,6 +594,7 @@  struct igb_adapter {
 	struct igb_mac_addr *mac_table;
 	struct vf_mac_filter vf_macs;
 	struct vf_mac_filter *vf_mac_list;
+	bool rx_drop_enable; /* drop packets when descriptor ring exhausted */
 };
 
 /* flags controlling PTP/1588 function */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 105b0624081a..5b499130c3f5 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2982,6 +2982,54 @@  static s32 igb_init_i2c(struct igb_adapter *adapter)
 	return status;
 }
 
+static ssize_t rx_drop_en_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
+
+{
+	struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+	struct igb_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->rx_drop_enable)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t rx_drop_en_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+	struct igb_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int queue_idx, reg_idx;
+	bool val;
+	u32 srrctl;
+	int ret;
+
+	ret = kstrtobool(buf, &val);
+	if (ret < 0)
+		return ret;
+
+	adapter->rx_drop_enable = val;
+
+	/* set for each currently active ring */
+	for (queue_idx = 0; queue_idx < adapter->num_rx_queues; queue_idx++) {
+		reg_idx = adapter->rx_ring[queue_idx]->reg_idx;
+		srrctl = rd32(E1000_SRRCTL(reg_idx));
+		if (val == 0)
+			srrctl &= ~E1000_SRRCTL_DROP_EN;
+		else
+			srrctl |= E1000_SRRCTL_DROP_EN;
+		wr32(E1000_SRRCTL(reg_idx), srrctl);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(rx_drop_en);
+
 /**
  *  igb_probe - Device Initialization Routine
  *  @pdev: PCI device information struct
@@ -3329,6 +3377,9 @@  static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto err_eeprom;
 	}
 
+	/* Add adapter attributes */
+	device_create_file(&pdev->dev, &dev_attr_rx_drop_en);
+
 	/* let the f/w know that the h/w is now under the control of the
 	 * driver.
 	 */
@@ -3655,6 +3706,9 @@  static void igb_remove(struct pci_dev *pdev)
 	 */
 	igb_release_hw_control(adapter);
 
+	/* Remove addapter attributes */
+	device_remove_file(&pdev->dev, &dev_attr_rx_drop_en);
+
 #ifdef CONFIG_PCI_IOV
 	igb_disable_sriov(pdev);
 #endif
@@ -3753,6 +3807,9 @@  static void igb_init_queue_configuration(struct igb_adapter *adapter)
 	max_rss_queues = igb_get_max_rss_queues(adapter);
 	adapter->rss_queues = min_t(u32, max_rss_queues, num_online_cpus());
 
+	if (adapter->vfs_allocated_count || adapter->rss_queues > 1)
+		adapter->rx_drop_enable = true;
+
 	igb_set_flag_queue_pairs(adapter, max_rss_queues);
 }
 
@@ -4504,7 +4561,8 @@  void igb_configure_rx_ring(struct igb_adapter *adapter,
 	if (hw->mac.type >= e1000_82580)
 		srrctl |= E1000_SRRCTL_TIMESTAMP;
 	/* Only set Drop Enable if we are supporting multiple queues */
-	if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
+	if (adapter->rx_drop_enable &&
+		(adapter->vfs_allocated_count || adapter->num_rx_queues > 1))
 		srrctl |= E1000_SRRCTL_DROP_EN;
 
 	wr32(E1000_SRRCTL(reg_idx), srrctl);