lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100323000519.19902.14802.stgit@localhost.localdomain>
Date:	Mon, 22 Mar 2010 17:06:20 -0700
From:	Jeff Kirsher <jeffrey.t.kirsher@...el.com>
To:	davem@...emloft.net
Cc:	netdev@...r.kernel.org, gospo@...hat.com,
	Nicholas Nunley <nicholasx.d.nunley@...el.com>,
	Jeff Kirsher <jeffrey.t.kirsher@...el.com>
Subject: [net-next-2.6 PATCH] igb: add IntMode module parameter

From: Nick Nunley <nicholasx.d.nunley@...el.com>

This patch adds the IntMode module parameter to igb. This
allows user selection of interrupt mode (MSI-X, MSI, legacy)
on driver load.

Signed-off-by: Nicholas Nunley <nicholasx.d.nunley@...el.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@...el.com>
---

 drivers/net/igb/Makefile    |    3 +
 drivers/net/igb/igb.h       |    7 ++
 drivers/net/igb/igb_main.c  |  125 ++++++++++++++++++++++++----------------
 drivers/net/igb/igb_param.c |  133 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 215 insertions(+), 53 deletions(-)
 create mode 100644 drivers/net/igb/igb_param.c

diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
index 8372cb9..049255e 100644
--- a/drivers/net/igb/Makefile
+++ b/drivers/net/igb/Makefile
@@ -33,5 +33,6 @@
 obj-$(CONFIG_IGB) += igb.o
 
 igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
-	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o
+	    e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o \
+	    igb_param.o
 
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index a177570..78a9c28 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -43,6 +43,11 @@ struct igb_adapter;
 /* ((1000000000ns / (6000ints/s * 1024ns)) << 2 = 648 */
 #define IGB_START_ITR 648
 
+/* Interrupt modes, as used by the IntMode paramter */
+#define IGB_INT_MODE_LEGACY                0
+#define IGB_INT_MODE_MSI                   1
+#define IGB_INT_MODE_MSIX                  2
+
 /* TX/RX descriptor defines */
 #define IGB_DEFAULT_TXD                  256
 #define IGB_MIN_TXD                       80
@@ -314,6 +319,7 @@ struct igb_adapter {
 	u16 rx_ring_count;
 	unsigned int vfs_allocated_count;
 	struct vf_data_storage *vf_data;
+	int int_mode;
 	u32 rss_queues;
 };
 
@@ -358,6 +364,7 @@ extern void igb_alloc_rx_buffers_adv(struct igb_ring *, int);
 extern void igb_update_stats(struct igb_adapter *);
 extern bool igb_has_link(struct igb_adapter *adapter);
 extern void igb_set_ethtool_ops(struct net_device *);
+extern void igb_check_options(struct igb_adapter *);
 extern void igb_power_up_link(struct igb_adapter *);
 
 static inline s32 igb_reset_phy(struct e1000_hw *hw)
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 45a0e4f..83431e9 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -679,6 +679,7 @@ static void igb_clear_interrupt_scheme(struct igb_adapter *adapter)
  **/
 static void igb_set_interrupt_capability(struct igb_adapter *adapter)
 {
+	struct pci_dev *pdev = adapter->pdev;
 	int err;
 	int numvecs, i;
 
@@ -686,60 +687,74 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter)
 	adapter->num_rx_queues = adapter->rss_queues;
 	adapter->num_tx_queues = adapter->rss_queues;
 
-	/* start with one vector for every rx queue */
-	numvecs = adapter->num_rx_queues;
-
-	/* if tx handler is separate add 1 for every tx queue */
-	if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
-		numvecs += adapter->num_tx_queues;
-
-	/* store the number of vectors reserved for queues */
-	adapter->num_q_vectors = numvecs;
-
-	/* add 1 vector for link status interrupts */
-	numvecs++;
-	adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry),
-					GFP_KERNEL);
-	if (!adapter->msix_entries)
-		goto msi_only;
-
-	for (i = 0; i < numvecs; i++)
-		adapter->msix_entries[i].entry = i;
-
-	err = pci_enable_msix(adapter->pdev,
-			      adapter->msix_entries,
-			      numvecs);
-	if (err == 0)
-		goto out;
-
-	igb_reset_interrupt_capability(adapter);
-
-	/* If we can't do MSI-X, try MSI */
-msi_only:
+	switch (adapter->int_mode) {
+	case IGB_INT_MODE_MSIX:
+		/* start with one vector for every rx queue */
+		numvecs = adapter->num_rx_queues;
+
+		/* if tx handler is seperate add 1 for every tx queue */
+		if (!(adapter->flags & IGB_FLAG_QUEUE_PAIRS))
+			numvecs += adapter->num_tx_queues;
+
+		/* store the number of vectors reserved for queues */
+		adapter->num_q_vectors = numvecs;
+
+		/* add 1 vecotr for link status interrupts */
+		numvecs++;
+		adapter->msix_entries = kcalloc(numvecs,
+		                                sizeof(struct msix_entry),
+		                                GFP_KERNEL);
+		if (adapter->msix_entries) {
+			for (i = 0; i < numvecs; i++)
+				adapter->msix_entries[i].entry = i;
+
+			err = pci_enable_msix(pdev,
+			                      adapter->msix_entries, numvecs);
+			if (err == 0)
+				break;
+		}
+		/* MSI-X failed, so fall through and try MSI */
+		dev_warn(&pdev->dev, "Failed to initialize MSI-X interrupts. "
+		         "Falling back to MSI interrupts.\n");
+		igb_reset_interrupt_capability(adapter);
+	case IGB_INT_MODE_MSI:
+		if (!pci_enable_msi(pdev))
+			adapter->flags |= IGB_FLAG_HAS_MSI;
+		else
+			dev_warn(&pdev->dev, "Failed to initialize MSI "
+			         "interrupts.  Falling back to legacy "
+			         "interrupts.\n");
+		/* Fall through */
+	case IGB_INT_MODE_LEGACY:
 #ifdef CONFIG_PCI_IOV
-	/* disable SR-IOV for non MSI-X configurations */
-	if (adapter->vf_data) {
-		struct e1000_hw *hw = &adapter->hw;
-		/* disable iov and allow time for transactions to clear */
-		pci_disable_sriov(adapter->pdev);
-		msleep(500);
-
-		kfree(adapter->vf_data);
-		adapter->vf_data = NULL;
-		wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
-		msleep(100);
-		dev_info(&adapter->pdev->dev, "IOV Disabled\n");
-	}
+		/* disable SR-IOV for non MSI-X configurations */
+		if (adapter->vf_data) {
+			struct e1000_hw *hw = &adapter->hw;
+			/*
+			 *  disable iov and allow time for transactions
+			 *  to clear
+			*/
+			pci_disable_sriov(adapter->pdev);
+			msleep(500);
+
+			kfree(adapter->vf_data);
+			adapter->vf_data = NULL;
+			wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+			msleep(100);
+			dev_info(&adapter->pdev->dev, "IOV Disabled\n");
+		}
 #endif
-	adapter->vfs_allocated_count = 0;
-	adapter->rss_queues = 1;
-	adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
-	adapter->num_rx_queues = 1;
-	adapter->num_tx_queues = 1;
-	adapter->num_q_vectors = 1;
-	if (!pci_enable_msi(adapter->pdev))
-		adapter->flags |= IGB_FLAG_HAS_MSI;
-out:
+		/* disable advanced features and set number of queues to 1 */
+		adapter->vfs_allocated_count = 0;
+		adapter->rss_queues = 1;
+		adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
+		adapter->num_rx_queues = 1;
+		adapter->num_tx_queues = 1;
+		adapter->num_q_vectors = 1;
+		/* Don't do anything; this is system default */
+		break;
+	}
+
 	/* Notify the stack of the (possibly) reduced Tx Queue count. */
 	adapter->netdev->real_num_tx_queues = adapter->num_tx_queues;
 	return;
@@ -1411,6 +1426,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 	const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
 	unsigned long mmio_start, mmio_len;
 	int err, pci_using_dac;
+	static int cards_found;
 	u16 eeprom_apme_mask = IGB_EEPROM_APME;
 	u32 part_num;
 
@@ -1477,6 +1493,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
+	adapter->bd_number = cards_found;
+
 	netdev->mem_start = mmio_start;
 	netdev->mem_end = mmio_start + mmio_len;
 
@@ -1675,6 +1693,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
 		(adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy",
 		adapter->num_rx_queues, adapter->num_tx_queues);
 
+	cards_found++;
 	return 0;
 
 err_register:
@@ -1945,6 +1964,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
 	adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
 	adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
+	igb_check_options(adapter);
+
 #ifdef CONFIG_PCI_IOV
 	if (hw->mac.type == e1000_82576)
 		adapter->vfs_allocated_count = max_vfs;
diff --git a/drivers/net/igb/igb_param.c b/drivers/net/igb/igb_param.c
new file mode 100644
index 0000000..af9d07f
--- /dev/null
+++ b/drivers/net/igb/igb_param.c
@@ -0,0 +1,133 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2010 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@...ts.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+
+#include "igb.h"
+
+/*
+ * This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define IGB_MAX_NIC 32
+
+#define OPTION_UNSET   -1
+
+/*
+ * All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define IGB_PARAM_INIT { [0 ... IGB_MAX_NIC] = OPTION_UNSET }
+#define IGB_PARAM(X, desc)					\
+	static int __devinitdata X[IGB_MAX_NIC+1]		\
+		= IGB_PARAM_INIT;				\
+	static unsigned int num_##X;				\
+	module_param_array_named(X, X, int, &num_##X, 0);	\
+	MODULE_PARM_DESC(X, desc);
+
+/* IntMode (Interrupt Mode)
+ *
+ * Valid Range: 0 - 2
+ *
+ * Default Value: 2 (MSI-X)
+ */
+IGB_PARAM(IntMode, "Interrupt Mode");
+#define MAX_INTMODE		IGB_INT_MODE_MSIX
+#define MIN_INTMODE		IGB_INT_MODE_LEGACY
+
+struct igb_option {
+	const char *name;
+	const char *err;
+	int def;
+	int min;
+	int max;
+};
+
+static int __devinit igb_validate_option(unsigned int *value,
+					   const struct igb_option *opt,
+					   struct igb_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	if (*value >= opt->min && *value <= opt->max) {
+		dev_info(&pdev->dev, "%s set to %d\n", opt->name, *value);
+		return 0;
+	} else {
+		dev_info(&pdev->dev, "Invalid %s value specified (%d) %s\n",
+		    opt->name, *value, opt->err);
+		*value = opt->def;
+		return -1;
+	}
+}
+
+/**
+ * igb_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ **/
+void __devinit igb_check_options(struct igb_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int bd = adapter->bd_number;
+
+	if (bd >= IGB_MAX_NIC) {
+		dev_notice(&pdev->dev, "Warning: no configuration for "
+			   "board #%d\n", bd);
+		dev_notice(&pdev->dev, "Using defaults for all values\n");
+	}
+
+	{ /* Interrupt Mode */
+		struct igb_option opt = {
+			.name = "Interrupt Mode",
+			.err  = "defaulting to 2 (MSI-X)",
+			.def  = IGB_INT_MODE_MSIX,
+			.min = MIN_INTMODE,
+			.max = MAX_INTMODE
+		};
+
+		if (num_IntMode > bd) {
+			unsigned int int_mode = IntMode[bd];
+			igb_validate_option(&int_mode, &opt, adapter);
+			adapter->int_mode = int_mode;
+		} else {
+			adapter->int_mode = opt.def;
+		}
+	}
+}

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ