瀏覽代碼

gpu: host1x: Add locking to syncpt

Currently syncpoints are not locked by mutex and this causes races
if we are aggressively freeing and allocating syncpoints.

This patch adds missing mutex protection to syncpoint structures.

Signed-off-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Shridhar Rasal <srasal@nvidia.com>
Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
[treding@nvidia.com: use better label names, don't reset local variable]
Signed-off-by: Thierry Reding <treding@nvidia.com>
Arto Merilainen 8 年之前
父節點
當前提交
d4b5781890
共有 2 個文件被更改,包括 21 次插入5 次删除
  1. 2 1
      drivers/gpu/host1x/dev.h
  2. 19 4
      drivers/gpu/host1x/syncpt.c

+ 2 - 1
drivers/gpu/host1x/dev.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2012-2013, NVIDIA Corporation.
+ * Copyright (c) 2012-2015, NVIDIA Corporation.
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * under the terms and conditions of the GNU General Public License,
@@ -120,6 +120,7 @@ struct host1x {
 
 
 	struct host1x_syncpt *nop_sp;
 	struct host1x_syncpt *nop_sp;
 
 
+	struct mutex syncpt_mutex;
 	struct mutex chlist_mutex;
 	struct mutex chlist_mutex;
 	struct host1x_channel chlist;
 	struct host1x_channel chlist;
 	unsigned long allocated_channels;
 	unsigned long allocated_channels;

+ 19 - 4
drivers/gpu/host1x/syncpt.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Tegra host1x Syncpoints
  * Tegra host1x Syncpoints
  *
  *
- * Copyright (c) 2010-2013, NVIDIA Corporation.
+ * Copyright (c) 2010-2015, NVIDIA Corporation.
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * under the terms and conditions of the GNU General Public License,
@@ -61,22 +61,24 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
 	struct host1x_syncpt *sp = host->syncpt;
 	struct host1x_syncpt *sp = host->syncpt;
 	char *name;
 	char *name;
 
 
+	mutex_lock(&host->syncpt_mutex);
+
 	for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
 	for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
 		;
 		;
 
 
 	if (i >= host->info->nb_pts)
 	if (i >= host->info->nb_pts)
-		return NULL;
+		goto unlock;
 
 
 	if (flags & HOST1X_SYNCPT_HAS_BASE) {
 	if (flags & HOST1X_SYNCPT_HAS_BASE) {
 		sp->base = host1x_syncpt_base_request(host);
 		sp->base = host1x_syncpt_base_request(host);
 		if (!sp->base)
 		if (!sp->base)
-			return NULL;
+			goto unlock;
 	}
 	}
 
 
 	name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id,
 	name = kasprintf(GFP_KERNEL, "%02u-%s", sp->id,
 			dev ? dev_name(dev) : NULL);
 			dev ? dev_name(dev) : NULL);
 	if (!name)
 	if (!name)
-		return NULL;
+		goto free_base;
 
 
 	sp->dev = dev;
 	sp->dev = dev;
 	sp->name = name;
 	sp->name = name;
@@ -86,7 +88,15 @@ static struct host1x_syncpt *host1x_syncpt_alloc(struct host1x *host,
 	else
 	else
 		sp->client_managed = false;
 		sp->client_managed = false;
 
 
+	mutex_unlock(&host->syncpt_mutex);
 	return sp;
 	return sp;
+
+free_base:
+	host1x_syncpt_base_free(sp->base);
+	sp->base = NULL;
+unlock:
+	mutex_unlock(&host->syncpt_mutex);
+	return NULL;
 }
 }
 
 
 u32 host1x_syncpt_id(struct host1x_syncpt *sp)
 u32 host1x_syncpt_id(struct host1x_syncpt *sp)
@@ -378,6 +388,7 @@ int host1x_syncpt_init(struct host1x *host)
 	for (i = 0; i < host->info->nb_bases; i++)
 	for (i = 0; i < host->info->nb_bases; i++)
 		bases[i].id = i;
 		bases[i].id = i;
 
 
+	mutex_init(&host->syncpt_mutex);
 	host->syncpt = syncpt;
 	host->syncpt = syncpt;
 	host->bases = bases;
 	host->bases = bases;
 
 
@@ -405,12 +416,16 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
 	if (!sp)
 	if (!sp)
 		return;
 		return;
 
 
+	mutex_lock(&sp->host->syncpt_mutex);
+
 	host1x_syncpt_base_free(sp->base);
 	host1x_syncpt_base_free(sp->base);
 	kfree(sp->name);
 	kfree(sp->name);
 	sp->base = NULL;
 	sp->base = NULL;
 	sp->dev = NULL;
 	sp->dev = NULL;
 	sp->name = NULL;
 	sp->name = NULL;
 	sp->client_managed = false;
 	sp->client_managed = false;
+
+	mutex_unlock(&sp->host->syncpt_mutex);
 }
 }
 EXPORT_SYMBOL(host1x_syncpt_free);
 EXPORT_SYMBOL(host1x_syncpt_free);