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

Commit a2dbb7b5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux

Pull drm fixes from Dave Airlie:
 "A bunch of change across the board, the main things are some vblank
  fallout in radeon and nouveau required some work, but I think this
  should fix it all.  There is also one drm fix for an oops in vmwgfx
  with how we pass the drm master around.

  The rest is just some amdgpu, i915, imx and rockchip fixes.

  Probably more than I'd like at this point, but hopefully things settle
  down now"

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux: (40 commits)
  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/nouveau: Fix pre-nv50 pageflip events (v4)
  drm: Fix an unwanted master inheritance v2
  drm/amdgpu: fix race condition in amd_sched_entity_push_job
  drm/amdgpu: add err check for pin userptr
  drm/i915: take a power domain reference while checking the HDMI live status
  drm/i915: add MISSING_CASE to a few port/aux power domain helpers
  drm/i915/ddi: fix intel_display_port_aux_power_domain() after HDMI detect
  drm/i915: Introduce a gmbus power domain
  drm/i915: Clean up AUX power domain handling
  drm/rockchip: Use CRTC vblank event interface
  drm/rockchip: Fix module autoload for OF platform driver
  drm/rockchip: vop: fix window origin calculation
  ...
parents 9cfe5212 df4d4aa9
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -539,6 +539,7 @@ struct amdgpu_bo {
	/* Constant after initialization */
	/* Constant after initialization */
	struct amdgpu_device		*adev;
	struct amdgpu_device		*adev;
	struct drm_gem_object		gem_base;
	struct drm_gem_object		gem_base;
	struct amdgpu_bo		*parent;


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


struct amdgpu_vm_manager {
struct amdgpu_vm_manager {
+4 −2
Original line number Original line 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);
				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;
				p->uf.offset = fence_data->offset;
			} else {
			} else {
				ret = -EINVAL;
				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]);
			amdgpu_ib_free(parser->adev, &parser->ibs[i]);
	kfree(parser->ibs);
	kfree(parser->ibs);
	if (parser->uf.bo)
	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,
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]);
			amdgpu_ib_free(job->adev, &job->ibs[i]);
	kfree(job->ibs);
	kfree(job->ibs);
	if (job->uf.bo)
	if (job->uf.bo)
		drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base);
		amdgpu_bo_unref(&job->uf.bo);
	return 0;
	return 0;
}
}


+79 −29
Original line number Original line 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;
	struct drm_crtc *crtc = &amdgpuCrtc->base;
	unsigned long flags;
	unsigned long flags;
	unsigned i;
	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);
	amdgpu_flip_wait_fence(adev, &work->excl);
	for (i = 0; i < work->shared_count; ++i)
	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 */
	/* We borrow the event spin lock for protecting flip_status */
	spin_lock_irqsave(&crtc->dev->event_lock, flags);
	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) */
	/* do the flip (mmio) */
	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
	adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
	/* set the flip status */
	/* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
	} else
	} else
		DRM_ERROR("failed to reserve buffer after flip\n");
		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->shared);
	kfree(work);
	kfree(work);
}
}
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
	obj = old_amdgpu_fb->obj;
	obj = old_amdgpu_fb->obj;


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


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


cleanup:
cleanup:
	drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
	amdgpu_bo_unref(&work->old_rbo);
	fence_put(work->excl);
	fence_put(work->excl);
	for (i = 0; i < work->shared_count; ++i)
	for (i = 0; i < work->shared_count; ++i)
		fence_put(work->shared[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 dev Device to query.
 * \param pipe Crtc to query.
 * \param pipe Crtc to query.
 * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
 * \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 *vpos Location where vertical scanout position should be stored.
 * \param *hpos Location where horizontal scanout position should go.
 * \param *hpos Location where horizontal scanout position should go.
 * \param *stime Target location for timestamp taken immediately before
 * \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;
		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. */
	/* Test scanout position against vblank region. */
	if ((*vpos < vbl_start) && (*vpos >= vbl_end))
	if ((*vpos < vbl_start) && (*vpos >= vbl_end))
		in_vbl = false;
		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:
	/* Check if inside vblank area and apply corrective offsets:
	 * vpos will then be >=0 in video scanout area, but negative
	 * vpos will then be >=0 in video scanout area, but negative
	 * within vblank area, counting down the number of lines until
	 * 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. */
	/* Correct for shifted end of vbl at vbl_end. */
	*vpos = *vpos - 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;
	return ret;
}
}


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


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


		/* if we want to write to it we must require anonymous
		/* if we want to write to it we must require anonymous
		   memory and install a MMU notifier */
		   memory and install a MMU notifier */
+47 −1
Original line number Original line 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)
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
{
{
	struct amdgpu_device *adev = dev->dev_private;
	struct amdgpu_device *adev = dev->dev_private;
	int vpos, hpos, stat;
	u32 count;


	if (pipe >= adev->mode_info.num_crtc) {
	if (pipe >= adev->mode_info.num_crtc) {
		DRM_ERROR("Invalid crtc %u\n", pipe);
		DRM_ERROR("Invalid crtc %u\n", pipe);
		return -EINVAL;
		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