Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7234d023 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering



Details of the problem, and solution, are in comments in the commit
proper.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 002d0c73
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -8,11 +8,23 @@
enum nv_subdev_type {
	NVDEV_SUBDEV_DEVICE,
	NVDEV_SUBDEV_VBIOS,

	/* All subdevs from DEVINIT to DEVINIT_LAST will be created before
	 * *any* of them are initialised.  This subdev category is used
	 * for any subdevs that the VBIOS init table parsing may call out
	 * to during POST.
	 */
	NVDEV_SUBDEV_DEVINIT,
	NVDEV_SUBDEV_GPIO,
	NVDEV_SUBDEV_I2C,
	NVDEV_SUBDEV_CLOCK,
	NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_CLOCK,

	/* This grouping of subdevs are initialised right after they've
	 * been created, and are allowed to assume any subdevs in the
	 * list above them exist and have been initialised.
	 */
	NVDEV_SUBDEV_MXM,
	NVDEV_SUBDEV_DEVINIT,
	NVDEV_SUBDEV_MC,
	NVDEV_SUBDEV_TIMER,
	NVDEV_SUBDEV_FB,
@@ -23,6 +35,7 @@ enum nv_subdev_type {
	NVDEV_SUBDEV_BAR,
	NVDEV_SUBDEV_VOLT,
	NVDEV_SUBDEV_THERM,

	NVDEV_ENGINE_DMAOBJ,
	NVDEV_ENGINE_FIFO,
	NVDEV_ENGINE_SW,
@@ -38,6 +51,7 @@ enum nv_subdev_type {
	NVDEV_ENGINE_UNK1C1,
	NVDEV_ENGINE_VENC,
	NVDEV_ENGINE_DISP,

	NVDEV_SUBDEV_NR,
};

+23 −15
Original line number Diff line number Diff line
@@ -96,14 +96,13 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
		    struct nouveau_object **pobject)
{
	struct nouveau_client *client = nv_client(parent);
	struct nouveau_object *subdev = NULL;
	struct nouveau_device *device;
	struct nouveau_devobj *devobj;
	struct nv_device_class *args = data;
	u64 disable, boot0, strap;
	u64 mmio_base, mmio_size;
	void __iomem *map;
	int ret, i;
	int ret, i, c;

	if (size < sizeof(struct nv_device_class))
		return -EINVAL;
@@ -234,34 +233,43 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
	}

	/* ensure requested subsystems are available for use */
	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
	for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) {
		if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
			continue;

		if (!device->subdev[i]) {
			ret = nouveau_object_ctor(nv_object(device), NULL,
						  oclass, NULL, i, &subdev);
						  oclass, NULL, i,
						  &devobj->subdev[i]);
			if (ret == -ENODEV)
				continue;
			if (ret)
				return ret;

			if (nv_iclass(subdev, NV_ENGINE_CLASS))
				nouveau_subdev_reset(subdev);
			if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS))
				nouveau_subdev_reset(devobj->subdev[i]);
		} else {
			nouveau_object_ref(device->subdev[i], &subdev);
			nouveau_object_ref(device->subdev[i],
					  &devobj->subdev[i]);
		}

		if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
		/* note: can't init *any* subdevs until devinit has been run
		 * due to not knowing exactly what the vbios init tables will
		 * mess with.  devinit also can't be run until all of its
		 * dependencies have been created.
		 *
		 * this code delays init of any subdev until all of devinit's
		 * dependencies have been created, and then initialises each
		 * subdev in turn as they're created.
		 */
		while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
			struct nouveau_object *subdev = devobj->subdev[c++];
			if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
				ret = nouveau_object_inc(subdev);
			if (ret) {
				nouveau_object_ref(NULL, &subdev);
				if (ret)
					return ret;
			}
		}

		nouveau_object_ref(subdev, &devobj->subdev[i]);
		nouveau_object_ref(NULL, &subdev);
	}

	return 0;