Commit f5cfbd99 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/fb: protect comptags with private mutex



nvkm_subdev.mutex is going away.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
parent 71ccf2a0
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -36,7 +36,11 @@ struct nvkm_fb {
	struct nvkm_blob vpr_scrubber;

	struct nvkm_ram *ram;
	struct nvkm_mm tags;

	struct {
		struct mutex mutex; /* protects mm and nvkm_memory::tags */
		struct nvkm_mm mm;
	} tags;

	struct {
		struct nvkm_fb_tile region[16];
+9 −9
Original line number Diff line number Diff line
@@ -33,13 +33,13 @@ nvkm_memory_tags_put(struct nvkm_memory *memory, struct nvkm_device *device,
	struct nvkm_fb *fb = device->fb;
	struct nvkm_tags *tags = *ptags;
	if (tags) {
		mutex_lock(&fb->subdev.mutex);
		mutex_lock(&fb->tags.mutex);
		if (refcount_dec_and_test(&tags->refcount)) {
			nvkm_mm_free(&fb->tags, &tags->mn);
			nvkm_mm_free(&fb->tags.mm, &tags->mn);
			kfree(memory->tags);
			memory->tags = NULL;
		}
		mutex_unlock(&fb->subdev.mutex);
		mutex_unlock(&fb->tags.mutex);
		*ptags = NULL;
	}
}
@@ -52,29 +52,29 @@ nvkm_memory_tags_get(struct nvkm_memory *memory, struct nvkm_device *device,
	struct nvkm_fb *fb = device->fb;
	struct nvkm_tags *tags;

	mutex_lock(&fb->subdev.mutex);
	mutex_lock(&fb->tags.mutex);
	if ((tags = memory->tags)) {
		/* If comptags exist for the memory, but a different amount
		 * than requested, the buffer is being mapped with settings
		 * that are incompatible with existing mappings.
		 */
		if (tags->mn && tags->mn->length != nr) {
			mutex_unlock(&fb->subdev.mutex);
			mutex_unlock(&fb->tags.mutex);
			return -EINVAL;
		}

		refcount_inc(&tags->refcount);
		mutex_unlock(&fb->subdev.mutex);
		mutex_unlock(&fb->tags.mutex);
		*ptags = tags;
		return 0;
	}

	if (!(tags = kmalloc(sizeof(*tags), GFP_KERNEL))) {
		mutex_unlock(&fb->subdev.mutex);
		mutex_unlock(&fb->tags.mutex);
		return -ENOMEM;
	}

	if (!nvkm_mm_head(&fb->tags, 0, 1, nr, nr, 1, &tags->mn)) {
	if (!nvkm_mm_head(&fb->tags.mm, 0, 1, nr, nr, 1, &tags->mn)) {
		if (clr)
			clr(device, tags->mn->offset, tags->mn->length);
	} else {
@@ -92,7 +92,7 @@ nvkm_memory_tags_get(struct nvkm_memory *memory, struct nvkm_device *device,

	refcount_set(&tags->refcount, 1);
	*ptags = memory->tags = tags;
	mutex_unlock(&fb->subdev.mutex);
	mutex_unlock(&fb->tags.mutex);
	return 0;
}

+6 −4
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ nvkm_fb_oneinit(struct nvkm_subdev *subdev)
		nvkm_debug(subdev, "%d comptags\n", tags);
	}

	return nvkm_mm_init(&fb->tags, 0, 0, tags, 1);
	return nvkm_mm_init(&fb->tags.mm, 0, 0, tags, 1);
}

static int
@@ -205,7 +205,9 @@ nvkm_fb_dtor(struct nvkm_subdev *subdev)
	for (i = 0; i < fb->tile.regions; i++)
		fb->func->tile.fini(fb, i, &fb->tile.region[i]);

	nvkm_mm_fini(&fb->tags);
	nvkm_mm_fini(&fb->tags.mm);
	mutex_destroy(&fb->tags.mutex);

	nvkm_ram_del(&fb->ram);

	nvkm_blob_dtor(&fb->vpr_scrubber);
@@ -230,8 +232,8 @@ nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device,
	nvkm_subdev_ctor(&nvkm_fb, device, index, &fb->subdev);
	fb->func = func;
	fb->tile.regions = fb->func->tile.regions;
	fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage",
				fb->func->default_bigpage);
	fb->page = nvkm_longopt(device->cfgopt, "NvFbBigPage", fb->func->default_bigpage);
	mutex_init(&fb->tags.mutex);
}

int
+2 −2
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ nv20_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
{
	u32 tiles = DIV_ROUND_UP(size, 0x40);
	u32 tags  = round_up(tiles / fb->ram->parts, 0x40);
	if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
	if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
		if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
		else              tile->zcomp = 0x04000000; /* Z24S8 */
		tile->zcomp |= tile->tag->offset;
@@ -63,7 +63,7 @@ nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile)
	tile->limit = 0;
	tile->pitch = 0;
	tile->zcomp = 0;
	nvkm_mm_free(&fb->tags, &tile->tag);
	nvkm_mm_free(&fb->tags.mm, &tile->tag);
}

void
+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags,
{
	u32 tiles = DIV_ROUND_UP(size, 0x40);
	u32 tags  = round_up(tiles / fb->ram->parts, 0x40);
	if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
	if (!nvkm_mm_head(&fb->tags.mm, 0, 1, tags, tags, 1, &tile->tag)) {
		if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
		else              tile->zcomp = 0x00200000; /* Z24S8 */
		tile->zcomp |= tile->tag->offset;
Loading