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

Commit 39c9bfb4 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nv50: prevent multiple init tables being parsed at the same time



With DVI and DP plugged, the DVI clock change interrupts being run can
cause DP link training to fail.  This adds a spinlock around init table
parsing to prevent this.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 1ee7698f
Loading
Loading
Loading
Loading
+9 −8
Original line number Original line Diff line number Diff line
@@ -3765,7 +3765,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
	 */
	 */


	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct init_exec iexec = {true, false};
	struct nvbios *bios = &dev_priv->VBIOS;
	struct nvbios *bios = &dev_priv->VBIOS;
	uint8_t *table = &bios->data[bios->display.script_table_ptr];
	uint8_t *table = &bios->data[bios->display.script_table_ptr];
	uint8_t *otable = NULL;
	uint8_t *otable = NULL;
@@ -3845,8 +3844,6 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}
	}
	}


	bios->display.output = dcbent;

	if (pxclk == 0) {
	if (pxclk == 0) {
		script = ROM16(otable[6]);
		script = ROM16(otable[6]);
		if (!script) {
		if (!script) {
@@ -3855,7 +3852,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}


		NV_TRACE(dev, "0x%04X: parsing output script 0\n", script);
		NV_TRACE(dev, "0x%04X: parsing output script 0\n", script);
		parse_init_table(bios, script, &iexec);
		nouveau_bios_run_init_table(dev, script, dcbent);
	} else
	} else
	if (pxclk == -1) {
	if (pxclk == -1) {
		script = ROM16(otable[8]);
		script = ROM16(otable[8]);
@@ -3865,7 +3862,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}


		NV_TRACE(dev, "0x%04X: parsing output script 1\n", script);
		NV_TRACE(dev, "0x%04X: parsing output script 1\n", script);
		parse_init_table(bios, script, &iexec);
		nouveau_bios_run_init_table(dev, script, dcbent);
	} else
	} else
	if (pxclk == -2) {
	if (pxclk == -2) {
		if (table[4] >= 12)
		if (table[4] >= 12)
@@ -3878,7 +3875,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}


		NV_TRACE(dev, "0x%04X: parsing output script 2\n", script);
		NV_TRACE(dev, "0x%04X: parsing output script 2\n", script);
		parse_init_table(bios, script, &iexec);
		nouveau_bios_run_init_table(dev, script, dcbent);
	} else
	} else
	if (pxclk > 0) {
	if (pxclk > 0) {
		script = ROM16(otable[table[4] + i*6 + 2]);
		script = ROM16(otable[table[4] + i*6 + 2]);
@@ -3890,7 +3887,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}


		NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script);
		NV_TRACE(dev, "0x%04X: parsing clock script 0\n", script);
		parse_init_table(bios, script, &iexec);
		nouveau_bios_run_init_table(dev, script, dcbent);
	} else
	} else
	if (pxclk < 0) {
	if (pxclk < 0) {
		script = ROM16(otable[table[4] + i*6 + 4]);
		script = ROM16(otable[table[4] + i*6 + 4]);
@@ -3902,7 +3899,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		}
		}


		NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script);
		NV_TRACE(dev, "0x%04X: parsing clock script 1\n", script);
		parse_init_table(bios, script, &iexec);
		nouveau_bios_run_init_table(dev, script, dcbent);
	}
	}


	return 0;
	return 0;
@@ -5864,10 +5861,13 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nvbios *bios = &dev_priv->VBIOS;
	struct nvbios *bios = &dev_priv->VBIOS;
	struct init_exec iexec = { true, false };
	struct init_exec iexec = { true, false };
	unsigned long flags;


	spin_lock_irqsave(&bios->lock, flags);
	bios->display.output = dcbent;
	bios->display.output = dcbent;
	parse_init_table(bios, table, &iexec);
	parse_init_table(bios, table, &iexec);
	bios->display.output = NULL;
	bios->display.output = NULL;
	spin_unlock_irqrestore(&bios->lock, flags);
}
}


static bool NVInitVBIOS(struct drm_device *dev)
static bool NVInitVBIOS(struct drm_device *dev)
@@ -5876,6 +5876,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
	struct nvbios *bios = &dev_priv->VBIOS;
	struct nvbios *bios = &dev_priv->VBIOS;


	memset(bios, 0, sizeof(struct nvbios));
	memset(bios, 0, sizeof(struct nvbios));
	spin_lock_init(&bios->lock);
	bios->dev = dev;
	bios->dev = dev;


	if (!NVShadowVBIOS(dev, bios->data))
	if (!NVShadowVBIOS(dev, bios->data))
+2 −0
Original line number Original line Diff line number Diff line
@@ -205,6 +205,8 @@ struct nvbios {
	struct drm_device *dev;
	struct drm_device *dev;
	struct nouveau_bios_info pub;
	struct nouveau_bios_info pub;


	spinlock_t lock;

	uint8_t data[NV_PROM_SIZE];
	uint8_t data[NV_PROM_SIZE];
	unsigned int length;
	unsigned int length;
	bool execute;
	bool execute;