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

Commit df4d4aa9 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-fixes-4.4' of git://people.freedesktop.org/~agd5f/linux into drm-next

A few more last minute fixes for 4.4 on top of my pull request from
earlier this week.  The big change here is a vblank regression fix due to
commit 4dfd6486 "drm: Use vblank timestamps to guesstimate how many vblanks
were missed".  Beyond that, a hotplug fix and a few VM fixes.

* 'drm-fixes-4.4' of git://people.freedesktop.org/~agd5f/linux:
  drm/amdgpu: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v3)
  drm/radeon: Fixup hw vblank counter/ts for new drm_update_vblank_count() (v2)
  drm/radeon: Retry DDC probing on DVI on failure if we got an HPD interrupt
  drm/amdgpu: add spin lock to protect freed list in vm (v2)
  drm/amdgpu: partially revert "drm/amdgpu: fix VM_CONTEXT*_PAGE_TABLE_END_ADDR" v2
  drm/amdgpu: take a BO reference for the user fence
  drm/amdgpu: take a BO reference in the display code
  drm/amdgpu: set snooped flags only on system addresses v2
  drm/amdgpu: fix race condition in amd_sched_entity_push_job
  drm/amdgpu: add err check for pin userptr
  add blacklist for thinkpad T40p
  drm/amdgpu: fix VM page table reference counting
  drm/amdgpu: fix userptr flags check
parents bbc8764f 8e36f9d3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -539,6 +539,7 @@ struct amdgpu_bo {
	/* Constant after initialization */
	struct amdgpu_device		*adev;
	struct drm_gem_object		gem_base;
	struct amdgpu_bo		*parent;

	struct ttm_bo_kmap_obj		dma_buf_vmap;
	pid_t				pid;
@@ -955,6 +956,8 @@ struct amdgpu_vm {
	struct amdgpu_vm_id	ids[AMDGPU_MAX_RINGS];
	/* for interval tree */
	spinlock_t		it_lock;
	/* protecting freed */
	spinlock_t		freed_lock;
};

struct amdgpu_vm_manager {
+4 −2
Original line number Diff line number Diff line
@@ -222,6 +222,8 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
				}

				p->uf.bo = gem_to_amdgpu_bo(gobj);
				amdgpu_bo_ref(p->uf.bo);
				drm_gem_object_unreference_unlocked(gobj);
				p->uf.offset = fence_data->offset;
			} else {
				ret = -EINVAL;
@@ -487,7 +489,7 @@ static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bo
			amdgpu_ib_free(parser->adev, &parser->ibs[i]);
	kfree(parser->ibs);
	if (parser->uf.bo)
		drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base);
		amdgpu_bo_unref(&parser->uf.bo);
}

static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
@@ -776,7 +778,7 @@ static int amdgpu_cs_free_job(struct amdgpu_job *job)
			amdgpu_ib_free(job->adev, &job->ibs[i]);
	kfree(job->ibs);
	if (job->uf.bo)
		drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base);
		amdgpu_bo_unref(&job->uf.bo);
	return 0;
}

+79 −29
Original line number Diff line number Diff line
@@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
	struct drm_crtc *crtc = &amdgpuCrtc->base;
	unsigned long flags;
	unsigned i;
	int vpos, hpos, stat, min_udelay;
	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];

	amdgpu_flip_wait_fence(adev, &work->excl);
	for (i = 0; i < work->shared_count; ++i)
@@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
	/* We borrow the event spin lock for protecting flip_status */
	spin_lock_irqsave(&crtc->dev->event_lock, flags);

	/* If this happens to execute within the "virtually extended" vblank
	 * interval before the start of the real vblank interval then it needs
	 * to delay programming the mmio flip until the real vblank is entered.
	 * This prevents completing a flip too early due to the way we fudge
	 * our vblank counter and vblank timestamps in order to work around the
	 * problem that the hw fires vblank interrupts before actual start of
	 * vblank (when line buffer refilling is done for a frame). It
	 * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
	 * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
	 *
	 * In practice this won't execute very often unless on very fast
	 * machines because the time window for this to happen is very small.
	 */
	for (;;) {
		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
		 * start in hpos, and to the "fudged earlier" vblank start in
		 * vpos.
		 */
		stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
						  GET_DISTANCE_TO_VBLANKSTART,
						  &vpos, &hpos, NULL, NULL,
						  &crtc->hwmode);

		if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
		    !(vpos >= 0 && hpos <= 0))
			break;

		/* Sleep at least until estimated real start of hw vblank */
		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
		usleep_range(min_udelay, 2 * min_udelay);
		spin_lock_irqsave(&crtc->dev->event_lock, flags);
	};

	/* do the flip (mmio) */
	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
	/* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
	} else
		DRM_ERROR("failed to reserve buffer after flip\n");

	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
	amdgpu_bo_unref(&work->old_rbo);
	kfree(work->shared);
	kfree(work);
}
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
	obj = old_amdgpu_fb->obj;

	/* take a reference to the old object */
	drm_gem_object_reference(obj);
	work->old_rbo = gem_to_amdgpu_bo(obj);
	amdgpu_bo_ref(work->old_rbo);

	new_amdgpu_fb = to_amdgpu_framebuffer(fb);
	obj = new_amdgpu_fb->obj;
@@ -222,7 +259,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
	amdgpu_bo_unreserve(new_rbo);

cleanup:
	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
	amdgpu_bo_unref(&work->old_rbo);
	fence_put(work->excl);
	for (i = 0; i < work->shared_count; ++i)
		fence_put(work->shared[i]);
@@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
 * \param dev Device to query.
 * \param pipe Crtc to query.
 * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
 *              For driver internal use only also supports these flags:
 *
 *              USE_REAL_VBLANKSTART to use the real start of vblank instead
 *              of a fudged earlier start of vblank.
 *
 *              GET_DISTANCE_TO_VBLANKSTART to return distance to the
 *              fudged earlier start of vblank in *vpos and the distance
 *              to true start of vblank in *hpos.
 *
 * \param *vpos Location where vertical scanout position should be stored.
 * \param *hpos Location where horizontal scanout position should go.
 * \param *stime Target location for timestamp taken immediately before
@@ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
		vbl_end = 0;
	}

	/* Called from driver internal vblank counter query code? */
	if (flags & GET_DISTANCE_TO_VBLANKSTART) {
	    /* Caller wants distance from real vbl_start in *hpos */
	    *hpos = *vpos - vbl_start;
	}

	/* Fudge vblank to start a few scanlines earlier to handle the
	 * problem that vblank irqs fire a few scanlines before start
	 * of vblank. Some driver internal callers need the true vblank
	 * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
	 *
	 * The cause of the "early" vblank irq is that the irq is triggered
	 * by the line buffer logic when the line buffer read position enters
	 * the vblank, whereas our crtc scanout position naturally lags the
	 * line buffer read position.
	 */
	if (!(flags & USE_REAL_VBLANKSTART))
		vbl_start -= adev->mode_info.crtcs[pipe]->lb_vblank_lead_lines;

	/* Test scanout position against vblank region. */
	if ((*vpos < vbl_start) && (*vpos >= vbl_end))
		in_vbl = false;

	/* In vblank? */
	if (in_vbl)
	    ret |= DRM_SCANOUTPOS_IN_VBLANK;

	/* Called from driver internal vblank counter query code? */
	if (flags & GET_DISTANCE_TO_VBLANKSTART) {
		/* Caller wants distance from fudged earlier vbl_start */
		*vpos -= vbl_start;
		return ret;
	}

	/* Check if inside vblank area and apply corrective offsets:
	 * vpos will then be >=0 in video scanout area, but negative
	 * within vblank area, counting down the number of lines until
@@ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
	/* Correct for shifted end of vbl at vbl_end. */
	*vpos = *vpos - vbl_end;

	/* In vblank? */
	if (in_vbl)
		ret |= DRM_SCANOUTPOS_IN_VBLANK;

	/* Is vpos outside nominal vblank area, but less than
	 * 1/100 of a frame height away from start of vblank?
	 * If so, assume this isn't a massively delayed vblank
	 * interrupt, but a vblank interrupt that fired a few
	 * microseconds before true start of vblank. Compensate
	 * by adding a full frame duration to the final timestamp.
	 * Happens, e.g., on ATI R500, R600.
	 *
	 * We only do this if DRM_CALLED_FROM_VBLIRQ.
	 */
	if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
		vbl_start = mode->crtc_vdisplay;
		vtotal = mode->crtc_vtotal;

		if (vbl_start - *vpos < vtotal / 100) {
			*vpos -= vtotal;

			/* Signal this correction as "applied". */
			ret |= 0x8;
		}
	}

	return ret;
}

+3 −2
Original line number Diff line number Diff line
@@ -235,8 +235,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
	    AMDGPU_GEM_USERPTR_REGISTER))
		return -EINVAL;

	if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
		   !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) {
	if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && (
	     !(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
	     !(args->flags & AMDGPU_GEM_USERPTR_REGISTER))) {

		/* if we want to write to it we must require anonymous
		   memory and install a MMU notifier */
+47 −1
Original line number Diff line number Diff line
@@ -611,13 +611,59 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev,
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
{
	struct amdgpu_device *adev = dev->dev_private;
	int vpos, hpos, stat;
	u32 count;

	if (pipe >= adev->mode_info.num_crtc) {
		DRM_ERROR("Invalid crtc %u\n", pipe);
		return -EINVAL;
	}

	return amdgpu_display_vblank_get_counter(adev, pipe);
	/* The hw increments its frame counter at start of vsync, not at start
	 * of vblank, as is required by DRM core vblank counter handling.
	 * Cook the hw count here to make it appear to the caller as if it
	 * incremented at start of vblank. We measure distance to start of
	 * vblank in vpos. vpos therefore will be >= 0 between start of vblank
	 * and start of vsync, so vpos >= 0 means to bump the hw frame counter
	 * result by 1 to give the proper appearance to caller.
	 */
	if (adev->mode_info.crtcs[pipe]) {
		/* Repeat readout if needed to provide stable result if
		 * we cross start of vsync during the queries.
		 */
		do {
			count = amdgpu_display_vblank_get_counter(adev, pipe);
			/* Ask amdgpu_get_crtc_scanoutpos to return vpos as
			 * distance to start of vblank, instead of regular
			 * vertical scanout pos.
			 */
			stat = amdgpu_get_crtc_scanoutpos(
				dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
				&vpos, &hpos, NULL, NULL,
				&adev->mode_info.crtcs[pipe]->base.hwmode);
		} while (count != amdgpu_display_vblank_get_counter(adev, pipe));

		if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
			DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
		} else {
			DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
				      pipe, vpos);

			/* Bump counter if we are at >= leading edge of vblank,
			 * but before vsync where vpos would turn negative and
			 * the hw counter really increments.
			 */
			if (vpos >= 0)
				count++;
		}
	} else {
		/* Fallback to use value as is. */
		count = amdgpu_display_vblank_get_counter(adev, pipe);
		DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
	}

	return count;
}

/**
Loading