Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2817

kernel-2.6.18-238.el5.src.rpm

From: Andy Gospodarek <gospo@redhat.com>
Date: Mon, 27 Sep 2010 17:49:57 -0400
Subject: [net] ixgbe: add option to control interrupt mode
Message-id: <1285609797-18000-1-git-send-email-gospo@redhat.com>
Patchwork-id: 28425
O-Subject: [RHEL5.6 PATCH] ixgbe: fix link issues and panic with shared
	interrupts for 82598
Bugzilla: 571495

An problem was recently discovered with some 82598 devices (though no
known occurrences on 82598 pcie add-on cards) and the only workaround
appears to be disabling MSI-X and switching to MSI or legacy interrupts.
Our only option to workaround this was to add an additional module
option so those that needed it could use it.

Additional module options to control the interrupt mode are not favored
upstream, so this is a case where we will diverge a small bit and add
this code to another file to try and keep the ixgbe driver as clean as
possible.

This patch was tested by myself and Intel.

This will resolve the request in RHBZ 571495.


diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
index cd3ddfa..72a8da6 100644
--- a/drivers/net/ixgbe/Makefile
+++ b/drivers/net/ixgbe/Makefile
@@ -34,4 +34,4 @@ obj-$(CONFIG_IXGBE) += ixgbe.o
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
               ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \
-              ixgbe_mbx.o
+              ixgbe_mbx.o ixgbe_param.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index e21d049..f5f4212 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -475,6 +475,7 @@ extern s32 ixgbe_atr_set_flex_byte_82599(struct ixgbe_atr_input *input,
 extern s32 ixgbe_atr_set_l4type_82599(struct ixgbe_atr_input *input,
                                       u8 l4type);
 extern void ixgbe_set_rx_mode(struct net_device *netdev);
+extern void ixgbe_check_options(struct ixgbe_adapter *adapter);
 #ifdef IXGBE_FCOE
 extern void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter);
 extern int ixgbe_fso(struct ixgbe_adapter *adapter,
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index be24f03..760bd56 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -4478,6 +4478,8 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 	int err = 0;
 	int vector, v_budget;
 
+	if (!(adapter->flags & IXGBE_FLAG_MSIX_CAPABLE))
+		goto try_msi;
 	/*
 	 * It's easy to be greedy for MSI-X vectors, but it really
 	 * doesn't do us much good if we have a lot more vectors
@@ -4519,6 +4521,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
 		ixgbe_disable_sriov(adapter);
 
 	ixgbe_set_num_queues(adapter);
+try_msi:
+	if (!(adapter->flags & IXGBE_FLAG_MSI_CAPABLE))
+		goto out;
 
 	err = pci_enable_msi(adapter->pdev);
 	if (!err) {
@@ -6627,6 +6632,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 		goto err_sw_init;
 	}
 
+	/* check module options */
+	ixgbe_check_options(adapter);
+
 	ixgbe_probe_vf(adapter, ii);
 
 	netdev->features = NETIF_F_SG |
diff --git a/drivers/net/ixgbe/ixgbe_param.c b/drivers/net/ixgbe/ixgbe_param.c
new file mode 100644
index 0000000..b6a5193
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_param.c
@@ -0,0 +1,155 @@
+/*******************************************************************************
+
+  Copyright(c) 2010 Red Hat.  All rights reserved.
+
+  Based on code from Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 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".
+
+*******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+#include "ixgbe.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define IXGBE_MAX_NIC 16
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  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 IXGBE_PARAM_INIT { [0 ... IXGBE_MAX_NIC] = OPTION_UNSET }
+#define IXGBE_PARAM(X, desc) \
+	static int __devinitdata X[IXGBE_MAX_NIC+1] = IXGBE_PARAM_INIT; \
+	static unsigned int num_##X; \
+	module_param_array_named(X, X, int, &num_##X, 0); \
+	MODULE_PARM_DESC(X, desc);
+
+/* Interrupt Mode
+ *
+ * Valid Range: 0-2
+ *  - 0 - Legacy Interrupt
+ *  - 1 - MSI Interrupt
+ *  - 2 - MSI-X Interrupt(s)
+ *
+ * Default Value: 2
+ */
+IXGBE_PARAM(IntMode, "Change Interrupt Mode (0=Legacy, 1=MSI, 2=MSI-X), default 2");
+#define IXGBE_INT_LEGACY		      0
+#define IXGBE_INT_MSI			      1
+#define IXGBE_INT_MSIX			      2
+#define IXGBE_DEFAULT_INT	 IXGBE_INT_MSIX
+
+struct ixgbe_option {
+	enum { enable_option, range_option, list_option } type;
+	const char *name;
+	const char *err;
+	int def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+	} arg;
+};
+
+static int __devinit ixgbe_validate_option(unsigned int *value,
+                                           struct ixgbe_option *opt)
+{
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+	if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+		printk(KERN_INFO "ixgbe: %s set to %d\n", opt->name, *value);
+		return 0;
+	}
+	printk(KERN_INFO "ixgbe: Invalid %s specified (%d),  %s\n",
+	       opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+/**
+ * ixgbe_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 ixgbe_check_options(struct ixgbe_adapter *adapter)
+{
+	int bd = adapter->bd_number;
+	u32 *aflags = &adapter->flags;
+
+	if (bd >= IXGBE_MAX_NIC) {
+		printk(KERN_NOTICE
+		       "Warning: no configuration for board #%d\n", bd);
+		printk(KERN_NOTICE "Using defaults for all values\n");
+	}
+
+	{ /* Interrupt Mode */
+		unsigned int i_mode;
+		static struct ixgbe_option opt = {
+			.type = range_option,
+			.name = "Interrupt Mode",
+			.err =
+			  "using default of "__MODULE_STRING(IXGBE_DEFAULT_INT),
+			.def = IXGBE_DEFAULT_INT,
+			.arg = { .r = { .min = IXGBE_INT_LEGACY,
+					.max = IXGBE_INT_MSIX}}
+		};
+		/* enable MSI/MSI-X capabilities by default */
+		*aflags |= IXGBE_FLAG_MSIX_CAPABLE;
+		*aflags |= IXGBE_FLAG_MSI_CAPABLE;
+
+		if (num_IntMode > bd) {
+			/* take the minimum of whatever was set */
+			i_mode = IntMode[bd];
+			ixgbe_validate_option(&i_mode, &opt);
+			switch (i_mode) {
+			case IXGBE_INT_MSIX:
+				break;
+			case IXGBE_INT_LEGACY:
+				*aflags &= ~IXGBE_FLAG_MSI_CAPABLE;
+				/* fall through */
+			case IXGBE_INT_MSI:
+				*aflags &= ~IXGBE_FLAG_MSIX_CAPABLE;
+				*aflags &= ~IXGBE_FLAG_RSS_ENABLED;
+				break;
+			default:
+				*aflags &= ~IXGBE_FLAG_MSIX_CAPABLE;
+				*aflags &= ~IXGBE_FLAG_MSI_CAPABLE;
+				break;
+			}
+		}
+		/* empty code line with semi-colon */ ;
+	}
+}