[ofw] [PATCH] mthca/mlx4: allow retrieving CA attributes with pageable memory

Sean Hefty sean.hefty at intel.com
Tue Aug 25 14:08:34 PDT 2009


Modify the HCA drivers to support querying for attributes using a pageable
buffer.  Since the query calls block, it seems appropriate for the calls to
allow pageable memory, rather than forcing the user to allocate a non-paged
buffer in order to obtain a list of attributes.  The problem stems from the HCA
drivers accessing a user's buffer after acquiring a spinlock that raise IRQL.

This fixes kernel crashes with both the winmad and winverbs drivers.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
The mthca patch is compile tested only.

We need this, or some fix, in winof 2.1.

Index: hw/mlx4/kernel/bus/core/cache.c
===================================================================
--- hw/mlx4/kernel/bus/core/cache.c	(revision 2342)
+++ hw/mlx4/kernel/bus/core/cache.c	(working copy)
@@ -80,9 +80,9 @@
 		      int               index,
 		      union ib_gid     *gid)
 {
+	union ib_gid cgid;
 	struct ib_gid_cache *cache;
 	unsigned long flags;
-	int ret = 0;
 
 	if (mlx4_is_barred(device->dma_device))
 		return -EFAULT;
@@ -94,14 +94,16 @@
 
 	cache = device->cache.gid_cache[port_num - start_port(device)];
 
-	if (index < 0 || index >= cache->table_len)
-		ret = -EINVAL;
-	else
-		*gid = cache->table[index];
-
+	if (index < 0 || index >= cache->table_len) {
+		read_unlock_irqrestore(&device->cache.lock, flags);
+		return -EINVAL;
+	}
+	
+	cgid = cache->table[index];
 	read_unlock_irqrestore(&device->cache.lock, flags);
+	*gid = cgid;
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(ib_get_cached_gid);
 
@@ -113,33 +115,34 @@
 	struct ib_gid_cache *cache;
 	unsigned long flags;
 	int p, i;
-	int ret = -ENOENT;
 
 	if (mlx4_is_barred(device->dma_device))
 		return -EFAULT;
 
-	*port_num = (u8)-1;
-	if (index)
-		*index = (u16)-1;
-
 	read_lock_irqsave(&device->cache.lock, &flags);
 
 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
 		cache = device->cache.gid_cache[p];
 		for (i = 0; i < cache->table_len; ++i) {
 			if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
-				*port_num = (u8)(p + start_port(device));
-				if (index)
-					*index = (u16)i;
-				ret = 0;
 				goto found;
 			}
 		}
 	}
+
+	read_unlock_irqrestore(&device->cache.lock, flags);
+	*port_num = (u8)-1;
+	if (index)
+		*index = (u16)-1;
+	return -ENOENT;
+
 found:
 	read_unlock_irqrestore(&device->cache.lock, flags);
+	*port_num = (u8)(p + start_port(device));
+	if (index)
+		*index = (u16)i;
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(ib_find_cached_gid);
 
@@ -149,8 +152,8 @@
 		       __be16           *pkey)
 {
 	struct ib_pkey_cache *cache;
+	__be16 cpkey;
 	unsigned long flags;
-	int ret = 0;
 
 	if (mlx4_is_barred(device->dma_device))
 		return -EFAULT;
@@ -162,14 +165,16 @@
 
 	cache = device->cache.pkey_cache[port_num - start_port(device)];
 
-	if (index < 0 || index >= cache->table_len)
-		ret = -EINVAL;
-	else
-		*pkey = cache->table[index];
+	if (index < 0 || index >= cache->table_len) {
+		read_unlock_irqrestore(&device->cache.lock, flags);
+		return -EINVAL;
+	}
 
+	cpkey = cache->table[index];
 	read_unlock_irqrestore(&device->cache.lock, flags);
+	*pkey = cpkey;
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(ib_get_cached_pkey);
 
@@ -181,7 +186,6 @@
 	struct ib_pkey_cache *cache;
 	unsigned long flags;
 	int i;
-	int ret = -ENOENT;
 
 	if (mlx4_is_barred(device->dma_device))
 		return -EFAULT;
@@ -197,14 +201,17 @@
 
 	for (i = 0; i < cache->table_len; ++i)
 		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
-			*index = (u16)i;
-			ret = 0;
-			break;
+			goto found;
 		}
 
 	read_unlock_irqrestore(&device->cache.lock, flags);
+	*index = (u16)-1;
+	return -ENOENT;
 
-	return ret;
+found:
+	read_unlock_irqrestore(&device->cache.lock, flags);
+	*index = (u16)i;
+	return 0;
 }
 EXPORT_SYMBOL(ib_find_cached_pkey);
 
@@ -213,14 +220,16 @@
 		      u8                *lmc)
 {
 	unsigned long flags;
+	u8 clmc;
 	int ret = 0;
 
 	if (port_num < start_port(device) || port_num > end_port(device))
 		return -EINVAL;
 
 	read_lock_irqsave(&device->cache.lock, &flags);
-	*lmc = device->cache.lmc_cache[port_num - start_port(device)];
+	clmc = device->cache.lmc_cache[port_num - start_port(device)];
 	read_unlock_irqrestore(&device->cache.lock, flags);
+	*lmc = clmc;
 
 	return ret;
 }
Index: hw/mthca/kernel/mt_cache.c
===================================================================
--- hw/mthca/kernel/mt_cache.c	(revision 2342)
+++ hw/mthca/kernel/mt_cache.c	(working copy)
@@ -71,8 +71,8 @@
 		      int               index,
 		      union ib_gid     *gid)
 {
+	union ib_gid cgid;
 	struct ib_gid_cache *cache;
-	int ret = 0;
 	SPIN_LOCK_PREP(lh);
 
 	// sanity checks
@@ -85,14 +85,16 @@
 
 	cache = device->cache.gid_cache[port_num - start_port(device)];
 
-	if (index < 0 || index >= cache->table_len)
-		ret = -EINVAL;
-	else
-		*gid = cache->table[index];
+	if (index < 0 || index >= cache->table_len) {
+		read_unlock_irqrestore(&lh);
+		return -EINVAL;
+	}
 
+	cgid = cache->table[index];
 	read_unlock_irqrestore(&lh);
+	*gid = cgid;
 
-	return ret;
+	return 0;
 }
 
 int ib_find_cached_gid(struct ib_device *device,
@@ -103,31 +105,32 @@
 	struct ib_gid_cache *cache;
 	int i;
 	u8 p;
-	int ret = -ENOENT;
 	SPIN_LOCK_PREP(lh);
 
-	*port_num = (u8)-1;
-	if (index)
-		*index = (u16)-1;
-
 	read_lock_irqsave(&device->cache.lock, &lh);
 
 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
 		cache = device->cache.gid_cache[p];
 		for (i = 0; i < cache->table_len; ++i) {
 			if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
-				*port_num = p + start_port(device);
-				if (index)
-					*index = (u16)i;
-				ret = 0;
 				goto found;
 			}
 		}
 	}
+
+	read_unlock_irqrestore(&lh);
+	*port_num = (u8)-1;
+	if (index)
+		*index = (u16)-1;
+	return -ENOENT;
+
 found:
 	read_unlock_irqrestore(&lh);
+	*port_num = p + start_port(device);
+	if (index)
+		*index = (u16)i;
 
-	return ret;
+	return 0;
 }
 
 int ib_get_cached_pkey(struct ib_device *device,
@@ -136,7 +139,7 @@
 		       __be16           *pkey)
 {
 	struct ib_pkey_cache *cache;
-	int ret = 0;
+	__be16 cpkey;
 	SPIN_LOCK_PREP(lh);
 
 	// sanity checks
@@ -149,14 +152,16 @@
 
 	cache = device->cache.pkey_cache[port_num - start_port(device)];
 
-	if (index < 0 || index >= cache->table_len)
-		ret = -EINVAL;
-	else
-		*pkey = cache->table[index];
+	if (index < 0 || index >= cache->table_len) {
+		read_unlock_irqrestore(&lh);
+		return -EINVAL;
+	}
 
+	cpkey = cache->table[index];
 	read_unlock_irqrestore(&lh);
+	*pkey = cpkey;
 
-	return ret;
+	return 0;
 }
 
 int ib_find_cached_pkey(struct ib_device *device,
@@ -166,7 +171,6 @@
 {
 	struct ib_pkey_cache *cache;
 	int i;
-	int ret = -ENOENT;
 	SPIN_LOCK_PREP(lh);
 
 	if (port_num < start_port(device) || port_num > end_port(device))
@@ -176,18 +180,19 @@
 
 	cache = device->cache.pkey_cache[port_num - start_port(device)];
 
-	*index = (u16)-1;
-
 	for (i = 0; i < cache->table_len; ++i)
 		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
-			*index = (u16)i;
-			ret = 0;
-			break;
+			goto found;
 		}
 
 	read_unlock_irqrestore(&lh);
+	*index = (u16)-1;
+	return -ENOENT;
 
-	return ret;
+found:
+	read_unlock_irqrestore(&lh);
+	*index = (u16)i;
+	return 0;
 }
 
 static void ib_cache_update(struct ib_device *device,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: hw-pagepool.diff
Type: application/octet-stream
Size: 6658 bytes
Desc: not available
URL: <http://lists.openfabrics.org/pipermail/ofw/attachments/20090825/a9899d98/attachment.obj>


More information about the ofw mailing list