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

Sean Hefty sean.hefty at intel.com
Thu Aug 27 11:42:30 PDT 2009


Any objection to committing this?  We need a fix for the winof 2.1 release.

Thanks,
Sean

>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,
>





More information about the ofw mailing list