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

Commit b5af7544 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel:
  drm/i915: Improve CRTDDC mapping by using VBT info
  drm/i915: Fix CPU-spinning hangs related to fence usage by using an LRU.
  drm/i915: Set crtc/clone mask in different output devices
  drm/i915: Always use SDVO_B detect bit for SDVO output detection.
  drm/i915: Fix typo that broke SVID1 in intel_sdvo_multifunc_encoder()
  drm/i915: Check if BIOS enabled dual-channel LVDS on 8xx, not only on 9xx
  drm/i915: Set the multiplier for SDVO on G33 platform
parents adda7661 db545019
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -222,6 +222,7 @@ typedef struct drm_i915_private {
	unsigned int edp_support:1;
	int lvds_ssc_freq;

	int crt_ddc_bus; /* -1 = unknown, else GPIO to use for CRT DDC */
	struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
	int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
	int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -384,6 +385,9 @@ typedef struct drm_i915_private {
		 */
		struct list_head inactive_list;

		/** LRU list of objects with fence regs on them. */
		struct list_head fence_list;

		/**
		 * List of breadcrumbs associated with GPU requests currently
		 * outstanding.
@@ -451,6 +455,9 @@ struct drm_i915_gem_object {
	/** This object's place on the active/flushing/inactive lists */
	struct list_head list;

	/** This object's place on the fenced object LRU */
	struct list_head fence_list;

	/**
	 * This is set if the object is on the active or flushing lists
	 * (has pending rendering), and is not set if it's on inactive (ready
+48 −38
Original line number Diff line number Diff line
@@ -978,6 +978,7 @@ int
i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct drm_i915_gem_set_domain *args = data;
	struct drm_gem_object *obj;
	uint32_t read_domains = args->read_domains;
@@ -1010,8 +1011,18 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
		 obj, obj->size, read_domains, write_domain);
#endif
	if (read_domains & I915_GEM_DOMAIN_GTT) {
		struct drm_i915_gem_object *obj_priv = obj->driver_private;

		ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);

		/* Update the LRU on the fence for the CPU access that's
		 * about to occur.
		 */
		if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
			list_move_tail(&obj_priv->fence_list,
				       &dev_priv->mm.fence_list);
		}

		/* Silently promote "you're not bound, there was nothing to do"
		 * to success, since the client was just asking us to
		 * make sure everything was done.
@@ -1155,8 +1166,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
	}

	/* Need a new fence register? */
	if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
	    obj_priv->tiling_mode != I915_TILING_NONE) {
	if (obj_priv->tiling_mode != I915_TILING_NONE) {
		ret = i915_gem_object_get_fence_reg(obj);
		if (ret) {
			mutex_unlock(&dev->struct_mutex);
@@ -2208,6 +2218,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
	struct drm_i915_gem_object *old_obj_priv = NULL;
	int i, ret, avail;

	/* Just update our place in the LRU if our fence is getting used. */
	if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
		list_move_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
		return 0;
	}

	switch (obj_priv->tiling_mode) {
	case I915_TILING_NONE:
		WARN(1, "allocating a fence for non-tiled object?\n");
@@ -2229,7 +2245,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
	}

	/* First try to find a free reg */
try_again:
	avail = 0;
	for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
		reg = &dev_priv->fence_regs[i];
@@ -2243,52 +2258,41 @@ try_again:

	/* None available, try to steal one or wait for a user to finish */
	if (i == dev_priv->num_fence_regs) {
		uint32_t seqno = dev_priv->mm.next_gem_seqno;
		struct drm_gem_object *old_obj = NULL;

		if (avail == 0)
			return -ENOSPC;

		for (i = dev_priv->fence_reg_start;
		     i < dev_priv->num_fence_regs; i++) {
			uint32_t this_seqno;
		list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
				    fence_list) {
			old_obj = old_obj_priv->obj;

			reg = &dev_priv->fence_regs[i];
			old_obj_priv = reg->obj->driver_private;
			reg = &dev_priv->fence_regs[old_obj_priv->fence_reg];

			if (old_obj_priv->pin_count)
				continue;

			/* Take a reference, as otherwise the wait_rendering
			 * below may cause the object to get freed out from
			 * under us.
			 */
			drm_gem_object_reference(old_obj);

			/* i915 uses fences for GPU access to tiled buffers */
			if (IS_I965G(dev) || !old_obj_priv->active)
				break;

			/* find the seqno of the first available fence */
			this_seqno = old_obj_priv->last_rendering_seqno;
			if (this_seqno != 0 &&
			    reg->obj->write_domain == 0 &&
			    i915_seqno_passed(seqno, this_seqno))
				seqno = this_seqno;
		}

		/*
		 * Now things get ugly... we have to wait for one of the
		 * objects to finish before trying again.
			/* This brings the object to the head of the LRU if it
			 * had been written to.  The only way this should
			 * result in us waiting longer than the expected
			 * optimal amount of time is if there was a
			 * fence-using buffer later that was read-only.
			 */
		if (i == dev_priv->num_fence_regs) {
			if (seqno == dev_priv->mm.next_gem_seqno) {
				i915_gem_flush(dev,
					       I915_GEM_GPU_DOMAINS,
					       I915_GEM_GPU_DOMAINS);
				seqno = i915_add_request(dev, NULL,
							 I915_GEM_GPU_DOMAINS);
				if (seqno == 0)
					return -ENOMEM;
			}

			ret = i915_wait_request(dev, seqno);
			if (ret)
			i915_gem_object_flush_gpu_write_domain(old_obj);
			ret = i915_gem_object_wait_rendering(old_obj);
			if (ret != 0)
				return ret;
			goto try_again;
			break;
		}

		/*
@@ -2296,10 +2300,15 @@ try_again:
		 * for this object next time we need it.
		 */
		i915_gem_release_mmap(reg->obj);
		i = old_obj_priv->fence_reg;
		old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
		list_del_init(&old_obj_priv->fence_list);
		drm_gem_object_unreference(old_obj);
	}

	obj_priv->fence_reg = i;
	list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);

	reg->obj = obj;

	if (IS_I965G(dev))
@@ -2342,6 +2351,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)

	dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
	obj_priv->fence_reg = I915_FENCE_REG_NONE;
	list_del_init(&obj_priv->fence_list);
}

/**
@@ -3595,9 +3605,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
	 * Pre-965 chips need a fence register set up in order to
	 * properly handle tiled surfaces.
	 */
	if (!IS_I965G(dev) &&
	    obj_priv->fence_reg == I915_FENCE_REG_NONE &&
	    obj_priv->tiling_mode != I915_TILING_NONE) {
	if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) {
		ret = i915_gem_object_get_fence_reg(obj);
		if (ret != 0) {
			if (ret != -EBUSY && ret != -ERESTARTSYS)
@@ -3806,6 +3814,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
	obj_priv->obj = obj;
	obj_priv->fence_reg = I915_FENCE_REG_NONE;
	INIT_LIST_HEAD(&obj_priv->list);
	INIT_LIST_HEAD(&obj_priv->fence_list);

	return 0;
}
@@ -4253,6 +4262,7 @@ i915_gem_load(struct drm_device *dev)
	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
	INIT_LIST_HEAD(&dev_priv->mm.request_list);
	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
	INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
			  i915_gem_retire_work_handler);
	dev_priv->mm.next_gem_seqno = 1;
+48 −3
Original line number Diff line number Diff line
@@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id)
	return NULL;
}

static u16
get_blocksize(void *p)
{
	u16 *block_ptr, block_size;

	block_ptr = (u16 *)((char *)p - 2);
	block_size = *block_ptr;
	return block_size;
}

static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
			struct lvds_dvo_timing *dvo_timing)
@@ -214,6 +224,41 @@ parse_general_features(struct drm_i915_private *dev_priv,
	}
}

static void
parse_general_definitions(struct drm_i915_private *dev_priv,
			  struct bdb_header *bdb)
{
	struct bdb_general_definitions *general;
	const int crt_bus_map_table[] = {
		GPIOB,
		GPIOA,
		GPIOC,
		GPIOD,
		GPIOE,
		GPIOF,
	};

	/* Set sensible defaults in case we can't find the general block
	   or it is the wrong chipset */
	dev_priv->crt_ddc_bus = -1;

	general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
	if (general) {
		u16 block_size = get_blocksize(general);
		if (block_size >= sizeof(*general)) {
			int bus_pin = general->crt_ddc_gmbus_pin;
			DRM_DEBUG("crt_ddc_bus_pin: %d\n", bus_pin);
			if ((bus_pin >= 1) && (bus_pin <= 6)) {
				dev_priv->crt_ddc_bus =
					crt_bus_map_table[bus_pin-1];
			}
		} else {
			DRM_DEBUG("BDB_GD too small (%d). Invalid.\n",
				  block_size);
		}
	}
}

static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
		       struct bdb_header *bdb)
@@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
	struct bdb_general_definitions *p_defs;
	struct child_device_config *p_child;
	int i, child_device_num, count;
	u16	block_size, *block_ptr;
	u16	block_size;

	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
	if (!p_defs) {
@@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
		return;
	}
	/* get the block size of general definitions */
	block_ptr = (u16 *)((char *)p_defs - 2);
	block_size = *block_ptr;
	block_size = get_blocksize(p_defs);
	/* get the number of child device */
	child_device_num = (block_size - sizeof(*p_defs)) /
				sizeof(*p_child);
@@ -362,6 +406,7 @@ intel_init_bios(struct drm_device *dev)

	/* Grab useful general definitions */
	parse_general_features(dev_priv, bdb);
	parse_general_definitions(dev_priv, bdb);
	parse_lfp_panel_data(dev_priv, bdb);
	parse_sdvo_panel_data(dev_priv, bdb);
	parse_sdvo_device_mapping(dev_priv, bdb);
+10 −1
Original line number Diff line number Diff line
@@ -508,6 +508,7 @@ void intel_crt_init(struct drm_device *dev)
{
	struct drm_connector *connector;
	struct intel_output *intel_output;
	struct drm_i915_private *dev_priv = dev->dev_private;
	u32 i2c_reg;

	intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
@@ -527,8 +528,12 @@ void intel_crt_init(struct drm_device *dev)
	/* Set up the DDC bus. */
	if (IS_IGDNG(dev))
		i2c_reg = PCH_GPIOA;
	else
	else {
		i2c_reg = GPIOA;
		/* Use VBT information for CRT DDC if available */
		if (dev_priv->crt_ddc_bus != -1)
			i2c_reg = dev_priv->crt_ddc_bus;
	}
	intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
	if (!intel_output->ddc_bus) {
		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
@@ -537,6 +542,10 @@ void intel_crt_init(struct drm_device *dev)
	}

	intel_output->type = INTEL_OUTPUT_ANALOG;
	intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
				   (1 << INTEL_ANALOG_CLONE_BIT) |
				   (1 << INTEL_SDVO_LVDS_CLONE_BIT);
	intel_output->crtc_mask = (1 << 0) | (1 << 1);
	connector->interlace_allowed = 0;
	connector->doublescan_allowed = 0;

+15 −56
Original line number Diff line number Diff line
@@ -666,7 +666,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
	intel_clock_t clock;
	int err = target;

	if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
	    (I915_READ(LVDS)) != 0) {
		/*
		 * For LVDS, if the panel is on, just rely on its current
@@ -2396,7 +2396,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
		if (is_sdvo) {
			dpll |= DPLL_DVO_HIGH_SPEED;
			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
			if (IS_I945G(dev) || IS_I945GM(dev))
			if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
			else if (IS_IGDNG(dev))
				dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
@@ -3170,7 +3170,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)

        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct intel_output *intel_output = to_intel_output(connector);
		if (type_mask & (1 << intel_output->type))
		if (type_mask & intel_output->clone_mask)
			index_mask |= (1 << entry);
		entry++;
	}
@@ -3218,30 +3218,30 @@ static void intel_setup_outputs(struct drm_device *dev)
			intel_dp_init(dev, PCH_DP_D);

	} else if (IS_I9XX(dev)) {
		int found;
		u32 reg;
		bool found = false;

		if (I915_READ(SDVOB) & SDVO_DETECTED) {
			found = intel_sdvo_init(dev, SDVOB);
			if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
				intel_hdmi_init(dev, SDVOB);

			if (!found && SUPPORTS_INTEGRATED_DP(dev))
				intel_dp_init(dev, DP_B);
		}

		/* Before G4X SDVOC doesn't have its own detect register */
		if (IS_G4X(dev))
			reg = SDVOC;
		else
			reg = SDVOB;

		if (I915_READ(reg) & SDVO_DETECTED) {
		if (I915_READ(SDVOB) & SDVO_DETECTED)
			found = intel_sdvo_init(dev, SDVOC);
			if (!found && SUPPORTS_INTEGRATED_HDMI(dev))

		if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {

			if (SUPPORTS_INTEGRATED_HDMI(dev))
				intel_hdmi_init(dev, SDVOC);
			if (!found && SUPPORTS_INTEGRATED_DP(dev))
			if (SUPPORTS_INTEGRATED_DP(dev))
				intel_dp_init(dev, DP_C);
		}

		if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
			intel_dp_init(dev, DP_D);
	} else
@@ -3253,51 +3253,10 @@ static void intel_setup_outputs(struct drm_device *dev)
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		struct intel_output *intel_output = to_intel_output(connector);
		struct drm_encoder *encoder = &intel_output->enc;
		int crtc_mask = 0, clone_mask = 0;

		/* valid crtcs */
		switch(intel_output->type) {
		case INTEL_OUTPUT_HDMI:
			crtc_mask = ((1 << 0)|
				     (1 << 1));
			clone_mask = ((1 << INTEL_OUTPUT_HDMI));
			break;
		case INTEL_OUTPUT_DVO:
		case INTEL_OUTPUT_SDVO:
			crtc_mask = ((1 << 0)|
				     (1 << 1));
			clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
				      (1 << INTEL_OUTPUT_DVO) |
				      (1 << INTEL_OUTPUT_SDVO));
			break;
		case INTEL_OUTPUT_ANALOG:
			crtc_mask = ((1 << 0)|
				     (1 << 1));
			clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
				      (1 << INTEL_OUTPUT_DVO) |
				      (1 << INTEL_OUTPUT_SDVO));
			break;
		case INTEL_OUTPUT_LVDS:
			crtc_mask = (1 << 1);
			clone_mask = (1 << INTEL_OUTPUT_LVDS);
			break;
		case INTEL_OUTPUT_TVOUT:
			crtc_mask = ((1 << 0) |
				     (1 << 1));
			clone_mask = (1 << INTEL_OUTPUT_TVOUT);
			break;
		case INTEL_OUTPUT_DISPLAYPORT:
			crtc_mask = ((1 << 0) |
				     (1 << 1));
			clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
			break;
		case INTEL_OUTPUT_EDP:
			crtc_mask = (1 << 1);
			clone_mask = (1 << INTEL_OUTPUT_EDP);
			break;
		}
		encoder->possible_crtcs = crtc_mask;
		encoder->possible_clones = intel_connector_clones(dev, clone_mask);
		encoder->possible_crtcs = intel_output->crtc_mask;
		encoder->possible_clones = intel_connector_clones(dev,
						intel_output->clone_mask);
	}
}

Loading