diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index 6e19ec8..f4feb71 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -51,6 +51,7 @@
 #include <linux/completion.h>
 #include <linux/kref.h>
 #include <linux/sched.h>
+#include <linux/moduleparam.h>
 
 #include "qib_common.h"
 #include "qib_verbs.h"
@@ -721,7 +722,7 @@ struct qib_devdata {
 	u64 __iomem *kregend;
 	/* physical address of chip for io_remap, etc. */
 	resource_size_t physaddr;
-	/* qib_cfgctxts pointers */
+	/* cfgctxts pointers */
 	struct qib_ctxtdata **rcd; /* Receive Context Data */
 
 	/* qib_pportdata, points to array of (physical) port-specific
@@ -1077,6 +1078,114 @@ struct qib_devdata {
 	struct tasklet_struct error_tasklet;
 };
 
+enum qib_mod_param_t {
+	qib_mod_param_drv,
+	qib_mod_param_unit,
+	qib_mod_param_port
+};
+
+typedef int (*param_set_func_t)(struct qib_devdata *, u8, u64);
+
+struct qib_mod_param {
+	const char *name;
+	enum qib_mod_param_t type;
+	param_set_func_t func;
+	ulong dflt;
+	struct list_head list;
+	struct list_head pport;
+};
+
+extern int qib_set_mod_param(const char *, struct kernel_param *);
+extern int qib_get_mod_param(char *, struct kernel_param *);
+extern u64 qib_read_mod_param(struct qib_mod_param *, u16, u8);
+extern void qib_clean_mod_param(void);
+
+#define MAX_QIB_PARAM_LEN 128
+/**
+ * QIB_MODPARAM_GLOBAL - define a global module parameter
+ * @N: name of the module parameter
+ *
+ * Define a global module parameter for use in multiple files.
+ */
+#define QIB_MODPARAM_GLOBAL(N) \
+extern struct qib_mod_param qmp_##N
+/**
+ * QIB_MODPARAM_DRV - define a driver-scope module parameter
+ * @N: name of the module parameter
+ * @D: default value
+ * @P: visibility in sysfs
+ * @S: description
+ *
+ * Define a driver-scope (global to the driver instance) module
+ * parameter.
+ */
+#define QIB_MODPARAM_DRV(N, D, P, S)				  \
+	struct qib_mod_param qmp_##N = {			  \
+		.name = __stringify(N),				  \
+		.type = qib_mod_param_drv,			  \
+		.dflt = (ulong)D,				  \
+		.pport = { NULL, NULL }				  \
+	};							  \
+	module_param_named(N, qmp_##N.dflt, ulong, P);		  \
+	MODULE_PARM_DESC(N, S " (dflt: " __stringify(D) ")")
+/**
+ * QIB_MODPARAM_UNIT - define a unit-scope module parameter
+ * @N: name of the module parameter
+ * @F: callback function for dynamic value settings
+ * @D: default value
+ * @P: visibility in sysfs
+ * @D: description
+ *
+ * Define a unit-scope module parameter. Unit-scope module
+ * parameters allows specifying individual values for each of the
+ * QIB units.
+ */
+#define QIB_MODPARAM_UNIT(N, F, D, P, S)			   \
+	struct qib_mod_param qmp_##N = {			   \
+		.name = __stringify(N),				   \
+		.func = ((P) & S_IWUGO ? F : NULL),		   \
+		.type = qib_mod_param_unit,			   \
+		.dflt = (ulong)D,				   \
+		.pport = { NULL, NULL }				   \
+	};							   \
+	module_param_call(N, qib_set_mod_param, qib_get_mod_param, \
+			  &qmp_##N, (P));			   \
+	MODULE_PARM_DESC(N, S " (dflt: " __stringify(D) ")")
+/**
+ * QIB_MODPARAM_PORT - define a port-scope module parameter
+ * @N: name of the module parameter
+ * @F: callback function for dynamic value settings
+ * @D: default value
+ * @P: visibility in sysfs
+ * @D: description
+ *
+ * Define a port-scope module parameter. Port-scope module
+ * parameters allow specifying individual values foe each of the
+ * ports on any of the QIB units.
+ */
+#define QIB_MODPARAM_PORT(N, F, D, P, S)			   \
+	struct qib_mod_param qmp_##N = {			   \
+		.name = __stringify(N),				   \
+		.func = ((P) & S_IWUGO ? F : NULL),		   \
+		.type = qib_mod_param_port,			   \
+		.dflt = (ulong)D,				   \
+		.pport = { NULL, NULL }				   \
+	};							   \
+	module_param_call(N, qib_set_mod_param, qib_get_mod_param, \
+			  &qmp_##N, (P));			   \
+	MODULE_PARM_DESC(N, S " (dflt: " __stringify(D) ")")
+/**
+ * QIB_MODPARAM_GET - retrieve a module parameter value
+ * @N: name of the module parameter
+ * @U: unit number
+ * @P: port number
+ *
+ * Get the value for the specific unit/port. The macro will return
+ * the correct value regardless of a specific value for the
+ * specified unit/port is present or the default should be used.
+ */
+#define QIB_MODPARAM_GET(N, U, P) qib_read_mod_param(&qmp_##N, U, P)
+
 /* hol_state values */
 #define QIB_HOL_UP       0
 #define QIB_HOL_INIT     1
@@ -1106,6 +1215,7 @@ struct qib_filedata {
 };
 
 extern struct list_head qib_dev_list;
+extern struct list_head qib_mod_param_list;
 extern spinlock_t qib_devs_lock;
 extern struct qib_devdata *qib_lookup(int unit);
 extern u32 qib_cpulist_count;
@@ -1437,11 +1547,10 @@ const char *qib_get_unit_name(int unit);
 #endif
 
 /* global module parameter variables */
-extern unsigned qib_ibmtu;
-extern ushort qib_cfgctxts;
-extern ushort qib_num_cfg_vls;
+QIB_MODPARAM_GLOBAL(ibmtu);
+QIB_MODPARAM_GLOBAL(cfgctxts);
+QIB_MODPARAM_GLOBAL(krcvqs);
 extern ushort qib_mini_init; /* If set, do few (ideally 0) writes to chip */
-extern unsigned qib_n_krcv_queues;
 extern unsigned qib_sdma_fetch_arb;
 extern unsigned qib_compat_ddr_negotiate;
 extern int qib_special_trigger;
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 8895cfe..1c0dfe6 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -42,6 +43,9 @@
 
 #include "qib.h"
 
+#undef pr_fmt
+#define pr_fmt(fmt) QIB_DRV_NAME " " fmt
+
 /*
  * The size has to be longer than this string, so we can append
  * board/chip information to it in the init code.
@@ -50,11 +54,21 @@ const char ib_qib_version[] = QIB_IDSTR "\n";
 
 DEFINE_SPINLOCK(qib_devs_lock);
 LIST_HEAD(qib_dev_list);
+LIST_HEAD(qib_mod_param_list);
 DEFINE_MUTEX(qib_mutex);	/* general driver use */
 
-unsigned qib_ibmtu;
-module_param_named(ibmtu, qib_ibmtu, uint, S_IRUGO);
-MODULE_PARM_DESC(ibmtu, "Set max IB MTU (0=2KB, 1=256, 2=512, ... 5=4096");
+/* Per-unit/port module parameter value structure
+ * linked to the qib_mod_param structure - one per
+ * unit/port */
+struct qib_mod_param_pport {
+	struct list_head list;
+	u16 unit;
+	u8 port;
+	u64 value;
+};
+
+QIB_MODPARAM_PORT(ibmtu, NULL, 5, S_IRUGO,
+		  "Set max IB MTU (0=2KB, 1=256, 2=512, ... 5=4096");
 
 unsigned qib_compat_ddr_negotiate = 1;
 module_param_named(compat_ddr_negotiate, qib_compat_ddr_negotiate, uint,
@@ -88,6 +102,178 @@ const char *qib_get_unit_name(int unit)
 	return iname;
 }
 
+int qib_set_mod_param(const char *str, struct kernel_param *kp)
+{
+	char *next = (char *)str, *tmp;
+	unsigned long val = 0, dft;
+	u32 unit = 0, port = 0;
+	struct qib_mod_param *param =
+		(struct qib_mod_param *)kp->arg;
+	struct qib_mod_param_pport *pport, *p;
+	int ret = 0;
+
+	if (strlen(str) >= MAX_QIB_PARAM_LEN) {
+		pr_warn("parameter value too long\n");
+		ret = -ENOSPC;
+		goto done;
+	}
+
+	/* qib_dev_list will be empty only when the driver is initially
+	 * loading. */
+	if (list_empty(&qib_dev_list) || !param->pport.next)
+		INIT_LIST_HEAD(&param->pport);
+	tmp = next;
+	dft = simple_strtoul(tmp, &next, 0);
+	if (next == tmp) {
+		pr_warn("invalid parameter value\n");
+		ret =  -EINVAL;
+		goto done;
+	}
+	/* clear any previously added port entries */
+	list_for_each_entry_safe(pport, p, &param->pport, list) {
+		list_del(&pport->list);
+		kfree(pport);
+	}
+	if (!*next || *next == '\n' || *next == ',')
+		param->dflt = dft;
+	else if (*next && *next == ':')
+		/* no default, rewind the string */
+		next = tmp;
+	else
+		pr_warn("invalid parameter value\n");
+	while (*next && next[1]) {
+		if (*next == ',')
+			tmp = ++next;
+		unit = simple_strtoul(tmp, &next, 0);
+		if (param->type == qib_mod_param_port) {
+			if (next == tmp || !*next || *next != ':') {
+				pr_warn("Invalid unit:port argument at \"%s\".\n",
+					tmp);
+				while (*next && *next++ != ',')
+					;
+				tmp = next;
+				continue;
+			}
+			tmp = ++next;
+			port = simple_strtoul(tmp, &next, 0);
+			if (!port) {
+				/* port numbers start at 1, 0 is invalid */
+				pr_warn("Invalid argument at \"%s\". Port numbers start at 1.\n",
+					tmp);
+				while (*next && *next++ != ',')
+					;
+				tmp = next;
+				continue;
+			}
+		}
+		if (next == tmp || *next != '=') {
+			pr_warn("Invalid %s argument at \"%s\".\n",
+				(param->type == qib_mod_param_port ?
+				"port" : "unit"), tmp);
+			while (*next && *next++ != ',')
+				;
+			tmp = next;
+			continue;
+		}
+		tmp = ++next;
+		val = simple_strtoul(tmp, &next, 0);
+		if (next == tmp) {
+			pr_warn("Invalid value string at \"%s\"\n", tmp);
+			while (*next && *next++ != ',')
+				;
+			tmp = next;
+			continue;
+		}
+		pport = kzalloc(sizeof(struct qib_mod_param_pport),
+				GFP_KERNEL);
+		if (!pport) {
+			pr_err("no memory for module parameter.\n");
+			ret =  -ENOMEM;
+			goto done;
+		}
+		pport->unit = unit;
+		pport->port = port;
+		pport->value = val;
+		list_add_tail(&pport->list, &param->pport);
+		if (!*next || *next == '\n')
+			break;
+		tmp = ++next;
+	}
+	/* add parameter to list so it can be cleaned up */
+	if (!param->list.next)
+		list_add(&param->list, &qib_mod_param_list);
+
+	if (param->func && qib_count_units(NULL, NULL)) {
+		struct qib_devdata *dd;
+		list_for_each_entry(pport, &param->pport, list) {
+			param_set_func_t setfunc = param->func;
+			list_for_each_entry(dd, &qib_dev_list, list)
+				if (dd->unit == pport->unit)
+					break;
+			if (!setfunc(dd, pport->port, pport->value))
+				pr_err("Error setting module parameter %s for IB%u:%u",
+				       param->name,
+				       pport->unit,
+				       pport->port);
+		}
+	}
+done:
+	return ret;
+}
+
+int qib_get_mod_param(char *buffer, struct kernel_param *kp)
+{
+	struct qib_mod_param *param =
+		(struct qib_mod_param *)kp->arg;
+	struct qib_mod_param_pport *pport;
+	char *p = buffer;
+	int s = 0;
+
+	s = scnprintf(p, PAGE_SIZE, "%lu", param->dflt);
+	p += s;
+
+	if (param->pport.next)
+		list_for_each_entry(pport, &param->pport, list) {
+			*p++ = ',';
+			if (param->type == qib_mod_param_unit)
+				s = scnprintf(p, PAGE_SIZE, "%u=%llu",
+					      pport->unit, pport->value);
+			else if (param->type == qib_mod_param_port)
+				s = scnprintf(p, PAGE_SIZE, "%u:%u=%llu",
+					      pport->unit, pport->port,
+					      pport->value);
+			p += s;
+		}
+	return strlen(buffer);
+}
+
+u64 qib_read_mod_param(struct qib_mod_param *param, u16 unit, u8 port)
+{
+	struct qib_mod_param_pport *pport;
+	u64 ret = param->dflt;
+
+	if (param->type != qib_mod_param_drv)
+		if (param->pport.next && !list_empty(&param->pport))
+			list_for_each_entry(pport, &param->pport, list)
+				if (pport->unit == unit &&
+				    pport->port == port)
+					ret = pport->value;
+	return ret;
+}
+
+void qib_clean_mod_param(void)
+{
+	struct qib_mod_param *p;
+	struct qib_mod_param_pport *pp, *pps;
+
+	list_for_each_entry(p, &qib_mod_param_list, list) {
+		list_for_each_entry_safe(pp, pps, &p->pport, list) {
+			list_del(&pp->list);
+			kfree(pp);
+		}
+	}
+}
+
 /*
  * Return count of units with at least one port ACTIVE.
  */
@@ -618,7 +804,8 @@ int qib_set_mtu(struct qib_pportdata *ppd, u16 arg)
 		ret = -EINVAL;
 		goto bail;
 	}
-	chk = ib_mtu_enum_to_int(qib_ibmtu);
+	chk = ib_mtu_enum_to_int(
+		QIB_MODPARAM_GET(ibmtu, ppd->dd->unit, ppd->port));
 	if (chk > 0 && arg > chk) {
 		ret = -EINVAL;
 		goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index 4d352b9..8af5bd3 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
- * All rights reserved.
+ * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2006 - 2012 QLogic Corporation.  All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -2062,9 +2062,10 @@ qib_6120_get_msgheader(struct qib_devdata *dd, __le32 *rhf_addr)
 
 static void qib_6120_config_ctxts(struct qib_devdata *dd)
 {
+	u32 nkrcvqs = QIB_MODPARAM_GET(krcvqs, dd->unit, 0);
 	dd->ctxtcnt = qib_read_kreg32(dd, kr_portcnt);
-	if (qib_n_krcv_queues > 1) {
-		dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
+	if (nkrcvqs > 1) {
+		dd->first_user_ctxt = nkrcvqs * dd->num_pports;
 		if (dd->first_user_ctxt > dd->ctxtcnt)
 			dd->first_user_ctxt = dd->ctxtcnt;
 		dd->qpn_mask = dd->first_user_ctxt <= 2 ? 2 : 6;
@@ -3124,7 +3125,7 @@ static void get_6120_chip_params(struct qib_devdata *dd)
 	dd->piosize2k = val & ~0U;
 	dd->piosize4k = val >> 32;
 
-	mtu = ib_mtu_enum_to_int(qib_ibmtu);
+	mtu = ib_mtu_enum_to_int(QIB_MODPARAM_GET(ibmtu, dd->unit, 1));
 	if (mtu == -1)
 		mtu = QIB_DEFAULT_MTU;
 	dd->pport->ibmtu = (u32)mtu;
@@ -3274,7 +3275,7 @@ static int init_6120_variables(struct qib_devdata *dd)
 	dd->rhf_offset = 0;
 
 	/* we always allocate at least 2048 bytes for eager buffers */
-	ret = ib_mtu_enum_to_int(qib_ibmtu);
+	ret = ib_mtu_enum_to_int(QIB_MODPARAM_GET(ibmtu, dd->unit, 1));
 	dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
 	BUG_ON(!is_power_of_2(dd->rcvegrbufsize));
 	dd->rcvegrbufsize_shift = ilog2(dd->rcvegrbufsize);
@@ -3314,7 +3315,6 @@ static int init_6120_variables(struct qib_devdata *dd)
 	if (qib_mini_init)
 		goto bail;
 
-	qib_num_cfg_vls = 1; /* if any 6120's, only one VL */
 
 	ret = qib_create_ctxts(dd);
 	init_6120_cntrnames(dd);
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 86a0ba7..f809281 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
- * All rights reserved.
+ * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
  * This software is available to you under a choice of one of two
@@ -2293,19 +2293,21 @@ static void qib_7220_config_ctxts(struct qib_devdata *dd)
 {
 	unsigned long flags;
 	u32 nchipctxts;
+	u32 cfgctxts = QIB_MODPARAM_GET(cfgctxts, dd->unit, 0);
+	u32 nkrcvqs = QIB_MODPARAM_GET(krcvqs, dd->unit, 0);
 
 	nchipctxts = qib_read_kreg32(dd, kr_portcnt);
 	dd->cspec->numctxts = nchipctxts;
-	if (qib_n_krcv_queues > 1) {
+	if (nkrcvqs > 1) {
 		dd->qpn_mask = 0x3e;
-		dd->first_user_ctxt = qib_n_krcv_queues * dd->num_pports;
+		dd->first_user_ctxt = nkrcvqs * dd->num_pports;
 		if (dd->first_user_ctxt > nchipctxts)
 			dd->first_user_ctxt = nchipctxts;
 	} else
 		dd->first_user_ctxt = dd->num_pports;
 	dd->n_krcv_queues = dd->first_user_ctxt;
 
-	if (!qib_cfgctxts) {
+	if (!cfgctxts) {
 		int nctxts = dd->first_user_ctxt + num_online_cpus();
 
 		if (nctxts <= 5)
@@ -2314,8 +2316,8 @@ static void qib_7220_config_ctxts(struct qib_devdata *dd)
 			dd->ctxtcnt = 9;
 		else if (nctxts <= nchipctxts)
 			dd->ctxtcnt = nchipctxts;
-	} else if (qib_cfgctxts <= nchipctxts)
-		dd->ctxtcnt = qib_cfgctxts;
+	} else if (cfgctxts <= nchipctxts)
+		dd->ctxtcnt = cfgctxts;
 	if (!dd->ctxtcnt) /* none of the above, set to max */
 		dd->ctxtcnt = nchipctxts;
 
@@ -3839,7 +3841,7 @@ static void get_7220_chip_params(struct qib_devdata *dd)
 	dd->piosize2k = val & ~0U;
 	dd->piosize4k = val >> 32;
 
-	mtu = ib_mtu_enum_to_int(qib_ibmtu);
+	mtu = ib_mtu_enum_to_int(QIB_MODPARAM_GET(ibmtu, dd->unit, 1));
 	if (mtu == -1)
 		mtu = QIB_DEFAULT_MTU;
 	dd->pport->ibmtu = (u32)mtu;
@@ -4078,15 +4080,13 @@ static int qib_init_7220_variables(struct qib_devdata *dd)
 	ppd->cpspec->chase_timer.function = reenable_7220_chase;
 	ppd->cpspec->chase_timer.data = (unsigned long)ppd;
 
-	qib_num_cfg_vls = 1; /* if any 7220's, only one VL */
-
 	dd->rcvhdrentsize = QIB_RCVHDR_ENTSIZE;
 	dd->rcvhdrsize = QIB_DFLT_RCVHDRSIZE;
 	dd->rhf_offset =
 		dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
 
 	/* we always allocate at least 2048 bytes for eager buffers */
-	ret = ib_mtu_enum_to_int(qib_ibmtu);
+	ret = ib_mtu_enum_to_int(QIB_MODPARAM_GET(ibmtu, dd->unit, 1));
 	dd->rcvegrbufsize = ret != -1 ? max(ret, 2048) : QIB_DEFAULT_MTU;
 	BUG_ON(!is_power_of_2(dd->rcvegrbufsize));
 	dd->rcvegrbufsize_shift = ilog2(dd->rcvegrbufsize);
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 78e8550..e04e0b6 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -100,9 +100,8 @@ static const unsigned sdma_idle_cnt = 64;
  * Number of VLs we are configured to use (to allow for more
  * credits per vl, etc.)
  */
-ushort qib_num_cfg_vls = 2;
-module_param_named(num_vls, qib_num_cfg_vls, ushort, S_IRUGO);
-MODULE_PARM_DESC(num_vls, "Set number of Virtual Lanes to use (1-8)");
+static QIB_MODPARAM_PORT(num_vls, NULL, 2, S_IRUGO,
+			 "Set number of Virtual Lanes to use (1-8)");
 
 static ushort qib_chase = 1;
 module_param_named(chase, qib_chase, ushort, S_IRUGO);
@@ -113,9 +112,8 @@ module_param_named(long_attenuation, qib_long_atten, ushort, S_IRUGO);
 MODULE_PARM_DESC(long_attenuation, \
 		 "attenuation cutoff (dB) for long copper cable setup");
 
-static ushort qib_singleport;
-module_param_named(singleport, qib_singleport, ushort, S_IRUGO);
-MODULE_PARM_DESC(singleport, "Use only IB port 1; more per-port buffer space");
+static QIB_MODPARAM_UNIT(singleport, NULL, 0, S_IRUGO,
+			 "Use only IB port 1; more per-port buffer space");
 
 static ushort qib_krcvq01_no_msi;
 module_param_named(krcvq01_no_msi, qib_krcvq01_no_msi, ushort, S_IRUGO);
@@ -3306,7 +3304,8 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd)
 		 dd->majrev, dd->minrev,
 		 (unsigned)SYM_FIELD(dd->revision, Revision_R, SW));
 
-	if (qib_singleport && (features >> PORT_SPD_CAP_SHIFT) & PORT_SPD_CAP) {
+	if (QIB_MODPARAM_GET(singleport, dd->unit, 0) &&
+	    (features >> PORT_SPD_CAP_SHIFT) & PORT_SPD_CAP) {
 		qib_devinfo(dd->pcidev, "IB%u: Forced to single port mode"
 			    " by module parameter\n", dd->unit);
 		features &= PORT_SPD_CAP;
@@ -3595,12 +3594,14 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
 {
 	unsigned long flags;
 	u32 nchipctxts;
+	u32 cfgctxts = QIB_MODPARAM_GET(cfgctxts, dd->unit, 0);
+	u32 nkrcvqs = QIB_MODPARAM_GET(krcvqs, dd->unit, 0);
 
 	nchipctxts = qib_read_kreg32(dd, kr_contextcnt);
 	dd->cspec->numctxts = nchipctxts;
-	if (qib_n_krcv_queues > 1 && dd->num_pports) {
+	if (nkrcvqs > 1 && dd->num_pports) {
 		dd->first_user_ctxt = NUM_IB_PORTS +
-			(qib_n_krcv_queues - 1) * dd->num_pports;
+			(nkrcvqs - 1) * dd->num_pports;
 		if (dd->first_user_ctxt > nchipctxts)
 			dd->first_user_ctxt = nchipctxts;
 		dd->n_krcv_queues = dd->first_user_ctxt / dd->num_pports;
@@ -3609,7 +3610,7 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
 		dd->n_krcv_queues = 1;
 	}
 
-	if (!qib_cfgctxts) {
+	if (!cfgctxts) {
 		int nctxts = dd->first_user_ctxt + num_online_cpus();
 
 		if (nctxts <= 6)
@@ -3618,10 +3619,10 @@ static void qib_7322_config_ctxts(struct qib_devdata *dd)
 			dd->ctxtcnt = 10;
 		else if (nctxts <= nchipctxts)
 			dd->ctxtcnt = nchipctxts;
-	} else if (qib_cfgctxts < dd->num_pports)
+	} else if (cfgctxts < dd->num_pports)
 		dd->ctxtcnt = dd->num_pports;
-	else if (qib_cfgctxts <= nchipctxts)
-		dd->ctxtcnt = qib_cfgctxts;
+	else if (cfgctxts <= nchipctxts)
+		dd->ctxtcnt = cfgctxts;
 	if (!dd->ctxtcnt) /* none of the above, set to max */
 		dd->ctxtcnt = nchipctxts;
 
@@ -5451,7 +5452,6 @@ static void get_7322_chip_params(struct qib_devdata *dd)
 {
 	u64 val;
 	u32 piobufs;
-	int mtu;
 
 	dd->palign = qib_read_kreg32(dd, kr_pagealign);
 
@@ -5470,11 +5470,10 @@ static void get_7322_chip_params(struct qib_devdata *dd)
 	dd->piosize2k = val & ~0U;
 	dd->piosize4k = val >> 32;
 
-	mtu = ib_mtu_enum_to_int(qib_ibmtu);
-	if (mtu == -1)
-		mtu = QIB_DEFAULT_MTU;
-	dd->pport[0].ibmtu = (u32)mtu;
-	dd->pport[1].ibmtu = (u32)mtu;
+	dd->pport[0].ibmtu = ib_mtu_enum_to_int(
+		QIB_MODPARAM_GET(ibmtu, dd->unit, 1));
+	dd->pport[1].ibmtu = ib_mtu_enum_to_int(
+		QIB_MODPARAM_GET(ibmtu, dd->unit, 2));
 
 	/* these may be adjusted in init_chip_wc_pat() */
 	dd->pio2kbase = (u32 __iomem *)
@@ -6073,7 +6072,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 {
 	struct qib_pportdata *ppd;
 	unsigned features, pidx, sbufcnt;
-	int ret, mtu;
+	int ret, maxmtu = 0;
 	u32 sbufs, updthresh;
 
 	/* pport structs are contiguous, allocated after devdata */
@@ -6150,10 +6149,6 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 	 */
 	qib_7322_set_baseaddrs(dd);
 
-	mtu = ib_mtu_enum_to_int(qib_ibmtu);
-	if (mtu == -1)
-		mtu = QIB_DEFAULT_MTU;
-
 	dd->cspec->int_enable_mask = QIB_I_BITSEXTANT;
 	/* all hwerrors become interrupts, unless special purposed */
 	dd->cspec->hwerrmask = ~0ULL;
@@ -6163,9 +6158,14 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 		~(SYM_MASK(HwErrMask, IBSerdesPClkNotDetectMask_0) |
 		  SYM_MASK(HwErrMask, IBSerdesPClkNotDetectMask_1) |
 		  HWE_MASK(LATriggered));
-
 	for (pidx = 0; pidx < NUM_IB_PORTS; ++pidx) {
 		struct qib_chippport_specific *cp = ppd->cpspec;
+		int mtu = ib_mtu_enum_to_int(
+			QIB_MODPARAM_GET(ibmtu, dd->unit, pidx+1));
+		u8 vls = QIB_MODPARAM_GET(num_vls, dd->unit, pidx+1);
+		if (mtu == -1)
+			mtu = QIB_DEFAULT_MTU;
+		maxmtu = max(maxmtu, mtu);
 		ppd->link_speed_supported = features & PORT_SPD_CAP;
 		features >>=  PORT_SPD_CAP_SHIFT;
 		if (!ppd->link_speed_supported) {
@@ -6219,7 +6219,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 		ppd->link_width_active = IB_WIDTH_4X;
 		ppd->link_speed_active = QIB_IB_SDR;
 		ppd->delay_mult = ib_rate_to_delay[IB_RATE_10_GBPS];
-		switch (qib_num_cfg_vls) {
+		switch (vls) {
 		case 1:
 			ppd->vls_supported = IB_VL_VL0;
 			break;
@@ -6229,8 +6229,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 		default:
 			qib_devinfo(dd->pcidev,
 				    "Invalid num_vls %u, using 4 VLs\n",
-				    qib_num_cfg_vls);
-			qib_num_cfg_vls = 4;
+				    vls);
 			/* fall through */
 		case 4:
 			ppd->vls_supported = IB_VL_VL0_3;
@@ -6242,9 +6241,8 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 				qib_devinfo(dd->pcidev,
 					    "Invalid num_vls %u for MTU %d "
 					    ", using 4 VLs\n",
-					    qib_num_cfg_vls, mtu);
+					    vls, mtu);
 				ppd->vls_supported = IB_VL_VL0_3;
-				qib_num_cfg_vls = 4;
 			}
 			break;
 		}
@@ -6294,7 +6292,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
 	dd->rhf_offset = dd->rcvhdrentsize - sizeof(u64) / sizeof(u32);
 
 	/* we always allocate at least 2048 bytes for eager buffers */
-	dd->rcvegrbufsize = max(mtu, 2048);
+	dd->rcvegrbufsize = max(maxmtu, 2048);
 	BUG_ON(!is_power_of_2(dd->rcvegrbufsize));
 	dd->rcvegrbufsize_shift = ilog2(dd->rcvegrbufsize);
 
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 24ad901..ea569a7 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -56,9 +56,8 @@
  * Number of ctxts we are configured to use (to allow for more pio
  * buffers per ctxt, etc.)  Zero means use chip value.
  */
-ushort qib_cfgctxts;
-module_param_named(cfgctxts, qib_cfgctxts, ushort, S_IRUGO);
-MODULE_PARM_DESC(cfgctxts, "Set max number of contexts to use");
+QIB_MODPARAM_UNIT(cfgctxts, NULL, 0, S_IRUGO,
+		  "Set max number of contexts to use");
 
 /*
  * If set, do not write to any regs if avoidable, hack to allow
@@ -68,9 +67,8 @@ ushort qib_mini_init;
 module_param_named(mini_init, qib_mini_init, ushort, S_IRUGO);
 MODULE_PARM_DESC(mini_init, "If set, do minimal diag init");
 
-unsigned qib_n_krcv_queues;
-module_param_named(krcvqs, qib_n_krcv_queues, uint, S_IRUGO);
-MODULE_PARM_DESC(krcvqs, "number of kernel receive queues per IB port");
+QIB_MODPARAM_PORT(krcvqs, NULL, 0, S_IRUGO,
+		  "number of kernel receive queues per IB port");
 
 unsigned qib_cc_table_size;
 module_param_named(cc_table_size, qib_cc_table_size, uint, S_IRUGO);
@@ -96,14 +94,15 @@ unsigned long *qib_cpulist;
 /* set number of contexts we'll actually use */
 void qib_set_ctxtcnt(struct qib_devdata *dd)
 {
-	if (!qib_cfgctxts) {
+	u64 val = QIB_MODPARAM_GET(cfgctxts, dd->unit, 0);
+	if (!val) {
 		dd->cfgctxts = dd->first_user_ctxt + num_online_cpus();
 		if (dd->cfgctxts > dd->ctxtcnt)
 			dd->cfgctxts = dd->ctxtcnt;
-	} else if (qib_cfgctxts < dd->num_pports)
+	} else if (val < dd->num_pports)
 		dd->cfgctxts = dd->ctxtcnt;
-	else if (qib_cfgctxts <= dd->ctxtcnt)
-		dd->cfgctxts = qib_cfgctxts;
+	else if (val <= dd->ctxtcnt)
+		dd->cfgctxts = val;
 	else
 		dd->cfgctxts = dd->ctxtcnt;
 	dd->freectxts = (dd->first_user_ctxt > dd->cfgctxts) ? 0 :
@@ -676,10 +675,10 @@ int qib_init(struct qib_devdata *dd, int reinit)
 		if (lastfail)
 			ret = lastfail;
 		ppd = dd->pport + pidx;
-		mtu = ib_mtu_enum_to_int(qib_ibmtu);
+		mtu = ib_mtu_enum_to_int(
+			QIB_MODPARAM_GET(ibmtu, dd->unit, ppd->port));
 		if (mtu == -1) {
 			mtu = QIB_DEFAULT_MTU;
-			qib_ibmtu = 0; /* don't leave invalid value */
 		}
 		/* set max we can ever have for this driver load */
 		ppd->init_ibmaxlen = min(mtu > 2048 ?
@@ -1231,6 +1230,7 @@ static void __exit qlogic_ib_cleanup(void)
 
 	idr_destroy(&qib_unit_table);
 	qib_dev_cleanup();
+	qib_clean_mod_param();
 }
 
 module_exit(qlogic_ib_cleanup);
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index 19f1e6c..58745f9 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -535,7 +535,8 @@ static int subn_get_portinfo(struct ib_smp *smp, struct ib_device *ibdev,
 	pip->vl_arb_low_cap =
 		dd->f_get_ib_cfg(ppd, QIB_IB_CFG_VL_LOW_CAP);
 	/* InitTypeReply = 0 */
-	pip->inittypereply_mtucap = qib_ibmtu ? qib_ibmtu : IB_MTU_4096;
+	pip->inittypereply_mtucap =
+		QIB_MODPARAM_GET(ibmtu, dd->unit, ppd->port);
 	/* HCAs ignore VLStallCount and HOQLife */
 	/* pip->vlstallcnt_hoqlife; */
 	pip->operationalvl_pei_peo_fpi_fpo =
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 790646e..27fc3e8 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2008, 2009 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2008 - 2012 QLogic Corporation. All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -500,9 +501,8 @@ static int val2fld(int wd, int mask)
 	return wd;
 }
 
-static int qib_pcie_coalesce;
-module_param_named(pcie_coalesce, qib_pcie_coalesce, int, S_IRUGO);
-MODULE_PARM_DESC(pcie_coalesce, "tune PCIe colescing on some Intel chipsets");
+static QIB_MODPARAM_UNIT(pcie_coalesce, NULL, 0, S_IRUGO,
+			 "tune PCIe colescing on some Intel chipsets");
 
 /*
  * Enable PCIe completion and data coalescing, on Intel 5x00 and 7300
@@ -518,7 +518,7 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
 	u16 devid;
 	u32 mask, bits, val;
 
-	if (!qib_pcie_coalesce)
+	if (!QIB_MODPARAM_GET(pcie_coalesce, dd->unit, 0))
 		return 0;
 
 	/* Find out supported and configured values for parent (root) */
@@ -577,9 +577,8 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
  * BIOS may not set PCIe bus-utilization parameters for best performance.
  * Check and optionally adjust them to maximize our throughput.
  */
-static int qib_pcie_caps;
-module_param_named(pcie_caps, qib_pcie_caps, int, S_IRUGO);
-MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)");
+static QIB_MODPARAM_UNIT(pcie_caps, NULL, 0, S_IRUGO,
+			 "Max PCIe tuning: Payload (4lsb), ReadReq (D4..7)");
 
 static int qib_tune_pcie_caps(struct qib_devdata *dd)
 {
@@ -589,6 +588,7 @@ static int qib_tune_pcie_caps(struct qib_devdata *dd)
 	u16 pcaps, pctl, ecaps, ectl;
 	int rc_sup, ep_sup;
 	int rc_cur, ep_cur;
+	int caps = QIB_MODPARAM_GET(pcie_caps, dd->unit, 0);
 
 	/* Find out supported and configured values for parent (root) */
 	parent = dd->pcidev->bus->self;
@@ -620,8 +620,8 @@ static int qib_tune_pcie_caps(struct qib_devdata *dd)
 	ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_PAYLOAD);
 
 	/* If Supported greater than limit in module param, limit it */
-	if (rc_sup > (qib_pcie_caps & 7))
-		rc_sup = qib_pcie_caps & 7;
+	if (rc_sup > (caps & 7))
+		rc_sup = caps & 7;
 	/* If less than (allowed, supported), bump root payload */
 	if (rc_sup > rc_cur) {
 		rc_cur = rc_sup;
@@ -643,8 +643,8 @@ static int qib_tune_pcie_caps(struct qib_devdata *dd)
 	 * which is code '5' (log2(4096) - 7)
 	 */
 	rc_sup = 5;
-	if (rc_sup > ((qib_pcie_caps >> 4) & 7))
-		rc_sup = (qib_pcie_caps >> 4) & 7;
+	if (rc_sup > ((caps >> 4) & 7))
+		rc_sup = (caps >> 4) & 7;
 	rc_cur = fld2val(pctl, PCI_EXP_DEVCTL_READRQ);
 	ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_READRQ);
 
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 56b4265..001034c 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1621,7 +1621,8 @@ static int qib_query_port(struct ib_device *ibdev, u8 port,
 	props->max_vl_num = qib_num_vls(ppd->vls_supported);
 	props->init_type_reply = 0;
 
-	props->max_mtu = qib_ibmtu ? qib_ibmtu : IB_MTU_4096;
+	props->max_mtu = QIB_MODPARAM_GET(ibmtu, dd->unit, ppd->port) ?
+		QIB_MODPARAM_GET(ibmtu, dd->unit, ppd->port) : IB_MTU_4096;
 	switch (ppd->ibmtu) {
 	case 4096:
 		mtu = IB_MTU_4096;
