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

Commit 8d586fe6 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge remote branch 'nouveau/for-airlied' of ../drm-nouveau-next into drm-linus

* 'nouveau/for-airlied' of ../drm-nouveau-next:
  drm/nv50: prevent switching off SOR when in use for DVI-over-DP
  drm/nv50: fail auxch transaction if reply count not what we expect
  drm/nouveau: fix failure path if userspace specifies no valid memtypes
  drm/nouveau: report LVDS as disconnected if lid closed
  drm/nv50: prevent accidently turning off encoders we're actually using
  drm/nv50: fix alignment of per-channel fifo cache
  drm/nouveau: Evict buffers in VRAM before freeing sgdma
  drm/nouveau: Acknowledge DMA_VTX_PROTECTION PGRAPH interrupts
  drm/nouveau: fix thinko in nv04_instmem.c
  drm/nouveau: fix a race condition in nouveau_dma_wait()
parents 1a961ce0 16226536
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -24,9 +24,12 @@
 *
 */

#include <acpi/button.h>

#include "drmP.h"
#include "drm_edid.h"
#include "drm_crtc_helper.h"

#include "nouveau_reg.h"
#include "nouveau_drv.h"
#include "nouveau_encoder.h"
@@ -235,6 +238,10 @@ nouveau_connector_detect(struct drm_connector *connector)
	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
		nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
	if (nv_encoder && nv_connector->native_mode) {
#ifdef CONFIG_ACPI
		if (!nouveau_ignorelid && !acpi_lid_open())
			return connector_status_disconnected;
#endif
		nouveau_connector_set_encoder(connector, nv_encoder);
		return connector_status_connected;
	}
+47 −29
Original line number Diff line number Diff line
@@ -126,47 +126,52 @@ OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
	chan->dma.cur += nr_dwords;
}

static inline bool
READ_GET(struct nouveau_channel *chan, uint32_t *get)
/* Fetch and adjust GPU GET pointer
 *
 * Returns:
 *  value >= 0, the adjusted GET pointer
 *  -EINVAL if GET pointer currently outside main push buffer
 *  -EBUSY if timeout exceeded
 */
static inline int
READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
{
	uint32_t val;

	val = nvchan_rd32(chan, chan->user_get);
	if (val < chan->pushbuf_base ||
	    val > chan->pushbuf_base + (chan->dma.max << 2)) {
		/* meaningless to dma_wait() except to know whether the
		 * GPU has stalled or not

	/* reset counter as long as GET is still advancing, this is
	 * to avoid misdetecting a GPU lockup if the GPU happens to
	 * just be processing an operation that takes a long time
	 */
		*get = val;
		return false;
	if (val != *prev_get) {
		*prev_get = val;
		*timeout = 0;
	}

	*get = (val - chan->pushbuf_base) >> 2;
	return true;
	if ((++*timeout & 0xff) == 0) {
		DRM_UDELAY(1);
		if (*timeout > 100000)
			return -EBUSY;
	}

	if (val < chan->pushbuf_base ||
	    val > chan->pushbuf_base + (chan->dma.max << 2))
		return -EINVAL;

	return (val - chan->pushbuf_base) >> 2;
}

int
nouveau_dma_wait(struct nouveau_channel *chan, int size)
{
	uint32_t get, prev_get = 0, cnt = 0;
	bool get_valid;
	uint32_t prev_get = 0, cnt = 0;
	int get;

	while (chan->dma.free < size) {
		/* reset counter as long as GET is still advancing, this is
		 * to avoid misdetecting a GPU lockup if the GPU happens to
		 * just be processing an operation that takes a long time
		 */
		get_valid = READ_GET(chan, &get);
		if (get != prev_get) {
			prev_get = get;
			cnt = 0;
		}

		if ((++cnt & 0xff) == 0) {
			DRM_UDELAY(1);
			if (cnt > 100000)
		get = READ_GET(chan, &prev_get, &cnt);
		if (unlikely(get == -EBUSY))
			return -EBUSY;
		}

		/* loop until we have a usable GET pointer.  the value
		 * we read from the GPU may be outside the main ring if
@@ -177,7 +182,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
		 * from the SKIPS area, so the code below doesn't have to deal
		 * with some fun corner cases.
		 */
		if (!get_valid || get < NOUVEAU_DMA_SKIPS)
		if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS)
			continue;

		if (get <= chan->dma.cur) {
@@ -203,6 +208,19 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
			 * after processing the currently pending commands.
			 */
			OUT_RING(chan, chan->pushbuf_base | 0x20000000);

			/* wait for GET to depart from the skips area.
			 * prevents writing GET==PUT and causing a race
			 * condition that causes us to think the GPU is
			 * idle when it's not.
			 */
			do {
				get = READ_GET(chan, &prev_get, &cnt);
				if (unlikely(get == -EBUSY))
					return -EBUSY;
				if (unlikely(get == -EINVAL))
					continue;
			} while (get <= NOUVEAU_DMA_SKIPS);
			WRITE_PUT(NOUVEAU_DMA_SKIPS);

			/* we're now submitting commands at the start of
+7 −1
Original line number Diff line number Diff line
@@ -490,7 +490,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
		if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
			NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
				 nv_rd32(dev, NV50_AUXCH_CTRL(index)));
			return -EBUSY;
			ret = -EBUSY;
			goto out;
		}

		udelay(400);
@@ -501,6 +502,11 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
			break;
	}

	if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
		ret = -EREMOTEIO;
		goto out;
	}

	if (cmd & 1) {
		for (i = 0; i < 4; i++) {
			data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
+4 −0
Original line number Diff line number Diff line
@@ -71,6 +71,10 @@ MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)");
int nouveau_uscript_tmds = -1;
module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400);

MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
int nouveau_ignorelid = 0;
module_param_named(ignorelid, nouveau_ignorelid, int, 0400);

MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
		 "\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
		 "\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
+1 −0
Original line number Diff line number Diff line
@@ -677,6 +677,7 @@ extern char *nouveau_tv_norm;
extern int nouveau_reg_debug;
extern char *nouveau_vbios;
extern int nouveau_ctxfw;
extern int nouveau_ignorelid;

/* nouveau_state.c */
extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
Loading