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

Commit 4c44323d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: lock correct mutex around object unreference.
  drm/i915: add support for physical memory objects
  drm/i915: make LVDS fixed mode a preferred mode
  drm: handle depth & bpp changes correctly
  drm: initial KMS config fixes
  drm/i915: setup sarea properly in master_priv
  drm/i915: set vblank enabled flag correctly across IRQ install/uninstall
  drm/i915: don't enable vblanks on disabled pipes
parents 50246dd4 34b8686e
Loading
Loading
Loading
Loading
+126 −49
Original line number Original line Diff line number Diff line
@@ -36,7 +36,7 @@
/*
/*
 * Detailed mode info for 800x600@60Hz
 * Detailed mode info for 800x600@60Hz
 */
 */
static struct drm_display_mode std_mode[] = {
static struct drm_display_mode std_modes[] = {
	{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
	{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
		   968, 1056, 0, 600, 601, 605, 628, 0,
		   968, 1056, 0, 600, 601, 605, 628, 0,
		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
@@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = {
 * changes have occurred.
 * changes have occurred.
 *
 *
 * FIXME: take into account monitor limits
 * FIXME: take into account monitor limits
 *
 * RETURNS:
 * Number of modes found on @connector.
 */
 */
void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
					    uint32_t maxX, uint32_t maxY)
					    uint32_t maxX, uint32_t maxY)
{
{
	struct drm_device *dev = connector->dev;
	struct drm_device *dev = connector->dev;
	struct drm_display_mode *mode, *t;
	struct drm_display_mode *mode, *t;
	struct drm_connector_helper_funcs *connector_funcs =
	struct drm_connector_helper_funcs *connector_funcs =
		connector->helper_private;
		connector->helper_private;
	int ret;
	int count = 0;


	DRM_DEBUG("%s\n", drm_get_connector_name(connector));
	DRM_DEBUG("%s\n", drm_get_connector_name(connector));
	/* set all modes to the unverified state */
	/* set all modes to the unverified state */
@@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
		DRM_DEBUG("%s is disconnected\n",
		DRM_DEBUG("%s is disconnected\n",
			  drm_get_connector_name(connector));
			  drm_get_connector_name(connector));
		/* TODO set EDID to NULL */
		/* TODO set EDID to NULL */
		return;
		return 0;
	}
	}


	ret = (*connector_funcs->get_modes)(connector);
	count = (*connector_funcs->get_modes)(connector);
	if (!count)
		return 0;


	if (ret) {
	drm_mode_connector_list_update(connector);
	drm_mode_connector_list_update(connector);
	}


	if (maxX && maxY)
	if (maxX && maxY)
		drm_mode_validate_size(dev, &connector->modes, maxX,
		drm_mode_validate_size(dev, &connector->modes, maxX,
@@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,


	drm_mode_prune_invalid(dev, &connector->modes, true);
	drm_mode_prune_invalid(dev, &connector->modes, true);


	if (list_empty(&connector->modes)) {
	if (list_empty(&connector->modes))
		struct drm_display_mode *stdmode;
		return 0;

		DRM_DEBUG("No valid modes on %s\n",
			  drm_get_connector_name(connector));

		/* Should we do this here ???
		 * When no valid EDID modes are available we end up
		 * here and bailed in the past, now we add a standard
		 * 640x480@60Hz mode and carry on.
		 */
		stdmode = drm_mode_duplicate(dev, &std_mode[0]);
		drm_mode_probed_add(connector, stdmode);
		drm_mode_list_concat(&connector->probed_modes,
				     &connector->modes);

		DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
			  drm_get_connector_name(connector));
	}


	drm_mode_sort(&connector->modes);
	drm_mode_sort(&connector->modes);


@@ -131,20 +117,58 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
		drm_mode_debug_printmodeline(mode);
		drm_mode_debug_printmodeline(mode);
	}
	}

	return count;
}
}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);


void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
				      uint32_t maxY)
				      uint32_t maxY)
{
{
	struct drm_connector *connector;
	struct drm_connector *connector;
	int count = 0;


	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		drm_helper_probe_single_connector_modes(connector, maxX, maxY);
		count += drm_helper_probe_single_connector_modes(connector,
								 maxX, maxY);
	}
	}

	return count;
}
}
EXPORT_SYMBOL(drm_helper_probe_connector_modes);
EXPORT_SYMBOL(drm_helper_probe_connector_modes);


static void drm_helper_add_std_modes(struct drm_device *dev,
				     struct drm_connector *connector)
{
	struct drm_display_mode *mode, *t;
	int i;

	for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
		struct drm_display_mode *stdmode;

		/*
		 * When no valid EDID modes are available we end up
		 * here and bailed in the past, now we add some standard
		 * modes and move on.
		 */
		stdmode = drm_mode_duplicate(dev, &std_modes[i]);
		drm_mode_probed_add(connector, stdmode);
		drm_mode_list_concat(&connector->probed_modes,
				     &connector->modes);

		DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
			  drm_get_connector_name(connector));
	}
	drm_mode_sort(&connector->modes);

	DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
	list_for_each_entry_safe(mode, t, &connector->modes, head) {
		mode->vrefresh = drm_mode_vrefresh(mode);

		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
		drm_mode_debug_printmodeline(mode);
	}
}


/**
/**
 * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
 * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
@@ -237,6 +261,8 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled)


	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		enabled[i] = drm_connector_enabled(connector, true);
		enabled[i] = drm_connector_enabled(connector, true);
		DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
			  enabled[i] ? "yes" : "no");
		any_enabled |= enabled[i];
		any_enabled |= enabled[i];
		i++;
		i++;
	}
	}
@@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev,
			continue;
			continue;
		}
		}


		DRM_DEBUG("looking for preferred mode on connector %d\n",
			  connector->base.id);

		modes[i] = drm_has_preferred_mode(connector, width, height);
		modes[i] = drm_has_preferred_mode(connector, width, height);
		if (!modes[i]) {
		/* No preferred modes, pick one off the list */
		if (!modes[i] && !list_empty(&connector->modes)) {
			list_for_each_entry(modes[i], &connector->modes, head)
			list_for_each_entry(modes[i], &connector->modes, head)
				break;
				break;
		}
		}
		DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
			  "none");
		i++;
		i++;
	}
	}
	return true;
	return true;
@@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
	int width, height;
	int width, height;
	int i, ret;
	int i, ret;


	DRM_DEBUG("\n");

	width = dev->mode_config.max_width;
	width = dev->mode_config.max_width;
	height = dev->mode_config.max_height;
	height = dev->mode_config.max_height;


@@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
	if (!ret)
	if (!ret)
		DRM_ERROR("Unable to find initial modes\n");
		DRM_ERROR("Unable to find initial modes\n");


	DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);

	drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
	drm_pick_crtcs(dev, crtcs, modes, 0, width, height);


	i = 0;
	i = 0;
@@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
		}
		}


		if (mode && crtc) {
		if (mode && crtc) {
			DRM_DEBUG("desired mode %s set on crtc %d\n",
				  mode->name, crtc->base.id);
			crtc->desired_mode = mode;
			crtc->desired_mode = mode;
			connector->encoder->crtc = crtc;
			connector->encoder->crtc = crtc;
		} else
		} else
@@ -442,6 +480,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
	int saved_x, saved_y;
	int saved_x, saved_y;
	struct drm_encoder *encoder;
	struct drm_encoder *encoder;
	bool ret = true;
	bool ret = true;
	bool depth_changed, bpp_changed;


	adjusted_mode = drm_mode_duplicate(dev, mode);
	adjusted_mode = drm_mode_duplicate(dev, mode);


@@ -450,6 +489,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
	if (!crtc->enabled)
	if (!crtc->enabled)
		return true;
		return true;


	if (old_fb && crtc->fb) {
		depth_changed = (old_fb->depth != crtc->fb->depth);
		bpp_changed = (old_fb->bits_per_pixel !=
			       crtc->fb->bits_per_pixel);
	} else {
		depth_changed = true;
		bpp_changed = true;
	}

	saved_mode = crtc->mode;
	saved_mode = crtc->mode;
	saved_x = crtc->x;
	saved_x = crtc->x;
	saved_y = crtc->y;
	saved_y = crtc->y;
@@ -462,7 +510,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
	crtc->y = y;
	crtc->y = y;


	if (drm_mode_equal(&saved_mode, &crtc->mode)) {
	if (drm_mode_equal(&saved_mode, &crtc->mode)) {
		if (saved_x != crtc->x || saved_y != crtc->y) {
		if (saved_x != crtc->x || saved_y != crtc->y ||
		    depth_changed || bpp_changed) {
			crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
			crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
						  old_fb);
						  old_fb);
			goto done;
			goto done;
@@ -568,8 +617,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
	struct drm_encoder **save_encoders, *new_encoder;
	struct drm_encoder **save_encoders, *new_encoder;
	struct drm_framebuffer *old_fb;
	struct drm_framebuffer *old_fb;
	bool save_enabled;
	bool save_enabled;
	bool changed = false;
	bool mode_changed = false;
	bool flip_or_move = false;
	bool fb_changed = false;
	struct drm_connector *connector;
	struct drm_connector *connector;
	int count = 0, ro, fail = 0;
	int count = 0, ro, fail = 0;
	struct drm_crtc_helper_funcs *crtc_funcs;
	struct drm_crtc_helper_funcs *crtc_funcs;
@@ -597,7 +646,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
	/* save previous config */
	/* save previous config */
	save_enabled = set->crtc->enabled;
	save_enabled = set->crtc->enabled;


	/* this is meant to be num_connector not num_crtc */
	/*
	 * We do mode_config.num_connectors here since we'll look at the
	 * CRTC and encoder associated with each connector later.
	 */
	save_crtcs = kzalloc(dev->mode_config.num_connector *
	save_crtcs = kzalloc(dev->mode_config.num_connector *
			     sizeof(struct drm_crtc *), GFP_KERNEL);
			     sizeof(struct drm_crtc *), GFP_KERNEL);
	if (!save_crtcs)
	if (!save_crtcs)
@@ -613,21 +665,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
	/* We should be able to check here if the fb has the same properties
	/* We should be able to check here if the fb has the same properties
	 * and then just flip_or_move it */
	 * and then just flip_or_move it */
	if (set->crtc->fb != set->fb) {
	if (set->crtc->fb != set->fb) {
		/* if we have no fb then its a change not a flip */
		/* If we have no fb then treat it as a full mode set */
		if (set->crtc->fb == NULL)
		if (set->crtc->fb == NULL)
			changed = true;
			mode_changed = true;
		else if ((set->fb->bits_per_pixel !=
			 set->crtc->fb->bits_per_pixel) ||
			 set->fb->depth != set->crtc->fb->depth)
			fb_changed = true;
		else
		else
			flip_or_move = true;
			fb_changed = true;
	}
	}


	if (set->x != set->crtc->x || set->y != set->crtc->y)
	if (set->x != set->crtc->x || set->y != set->crtc->y)
		flip_or_move = true;
		fb_changed = true;


	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
		DRM_DEBUG("modes are different\n");
		DRM_DEBUG("modes are different\n");
		drm_mode_debug_printmodeline(&set->crtc->mode);
		drm_mode_debug_printmodeline(&set->crtc->mode);
		drm_mode_debug_printmodeline(set->mode);
		drm_mode_debug_printmodeline(set->mode);
		changed = true;
		mode_changed = true;
	}
	}


	/* a) traverse passed in connector list and get encoders for them */
	/* a) traverse passed in connector list and get encoders for them */
@@ -650,7 +706,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
		}
		}


		if (new_encoder != connector->encoder) {
		if (new_encoder != connector->encoder) {
			changed = true;
			mode_changed = true;
			connector->encoder = new_encoder;
			connector->encoder = new_encoder;
		}
		}
	}
	}
@@ -677,16 +733,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
				new_crtc = set->crtc;
				new_crtc = set->crtc;
		}
		}
		if (new_crtc != connector->encoder->crtc) {
		if (new_crtc != connector->encoder->crtc) {
			changed = true;
			mode_changed = true;
			connector->encoder->crtc = new_crtc;
			connector->encoder->crtc = new_crtc;
		}
		}
	}
	}


	/* mode_set_base is not a required function */
	/* mode_set_base is not a required function */
	if (flip_or_move && !crtc_funcs->mode_set_base)
	if (fb_changed && !crtc_funcs->mode_set_base)
		changed = true;
		mode_changed = true;


	if (changed) {
	if (mode_changed) {
		old_fb = set->crtc->fb;
		old_fb = set->crtc->fb;
		set->crtc->fb = set->fb;
		set->crtc->fb = set->fb;
		set->crtc->enabled = (set->mode != NULL);
		set->crtc->enabled = (set->mode != NULL);
@@ -705,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
			set->crtc->desired_mode = set->mode;
			set->crtc->desired_mode = set->mode;
		}
		}
		drm_helper_disable_unused_functions(dev);
		drm_helper_disable_unused_functions(dev);
	} else if (flip_or_move) {
	} else if (fb_changed) {
		old_fb = set->crtc->fb;
		old_fb = set->crtc->fb;
		if (set->crtc->fb != set->fb)
		if (set->crtc->fb != set->fb)
			set->crtc->fb = set->fb;
			set->crtc->fb = set->fb;
@@ -764,10 +820,31 @@ bool drm_helper_plugged_event(struct drm_device *dev)
 */
 */
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
{
{
	int ret = false;
	struct drm_connector *connector;
	int count = 0;


	drm_helper_plugged_event(dev);
	count = drm_helper_probe_connector_modes(dev,
	return ret;
						 dev->mode_config.max_width,
						 dev->mode_config.max_height);

	/*
	 * None of the available connectors had any modes, so add some
	 * and try to light them up anyway
	 */
	if (!count) {
		DRM_ERROR("connectors have no modes, using standard modes\n");
		list_for_each_entry(connector,
				    &dev->mode_config.connector_list,
				    head)
			drm_helper_add_std_modes(dev, connector);
	}

	drm_setup_crtcs(dev);

	/* alert the driver fb layer */
	dev->mode_config.funcs->fb_changed(dev);

	return 0;
}
}
EXPORT_SYMBOL(drm_helper_initial_config);
EXPORT_SYMBOL(drm_helper_initial_config);


+15 −3
Original line number Original line Diff line number Diff line
@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
 */
 */
int drm_irq_uninstall(struct drm_device * dev)
int drm_irq_uninstall(struct drm_device * dev)
{
{
	int irq_enabled;
	unsigned long irqflags;
	int irq_enabled, i;


	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
		return -EINVAL;
		return -EINVAL;
@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
	dev->irq_enabled = 0;
	dev->irq_enabled = 0;
	mutex_unlock(&dev->struct_mutex);
	mutex_unlock(&dev->struct_mutex);


	/*
	 * Wake up any waiters so they don't hang.
	 */
	spin_lock_irqsave(&dev->vbl_lock, irqflags);
	for (i = 0; i < dev->num_crtcs; i++) {
		DRM_WAKEUP(&dev->vbl_queue[i]);
		dev->vblank_enabled[i] = 0;
	}
	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);

	if (!irq_enabled)
	if (!irq_enabled)
		return -EINVAL;
		return -EINVAL;


@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
			  vblwait->request.sequence, crtc);
			  vblwait->request.sequence, crtc);
		dev->last_vblank_wait[crtc] = vblwait->request.sequence;
		dev->last_vblank_wait[crtc] = vblwait->request.sequence;
		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
			    ((drm_vblank_count(dev, crtc)
			    (((drm_vblank_count(dev, crtc) -
			      - vblwait->request.sequence) <= (1 << 23)));
			       vblwait->request.sequence) <= (1 << 23)) ||
			     !dev->irq_enabled));


		if (ret != -EINTR) {
		if (ret != -EINTR) {
			struct timeval now;
			struct timeval now;
+10 −0
Original line number Original line Diff line number Diff line
@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;


	master_priv->sarea = drm_getsarea(dev);
	if (master_priv->sarea) {
		master_priv->sarea_priv = (drm_i915_sarea_t *)
			((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
	} else {
		DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
	}

	if (init->ring_size != 0) {
	if (init->ring_size != 0) {
		if (dev_priv->ring.ring_obj != NULL) {
		if (dev_priv->ring.ring_obj != NULL) {
			i915_dma_cleanup(dev);
			i915_dma_cleanup(dev);
@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev)
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		intel_modeset_cleanup(dev);
		intel_modeset_cleanup(dev);


		i915_gem_free_all_phys_object(dev);

		mutex_lock(&dev->struct_mutex);
		mutex_lock(&dev->struct_mutex);
		i915_gem_cleanup_ringbuffer(dev);
		i915_gem_cleanup_ringbuffer(dev);
		mutex_unlock(&dev->struct_mutex);
		mutex_unlock(&dev->struct_mutex);
+23 −0
Original line number Original line Diff line number Diff line
@@ -72,6 +72,18 @@ enum pipe {
#define WATCH_INACTIVE	0
#define WATCH_INACTIVE	0
#define WATCH_PWRITE	0
#define WATCH_PWRITE	0


#define I915_GEM_PHYS_CURSOR_0 1
#define I915_GEM_PHYS_CURSOR_1 2
#define I915_GEM_PHYS_OVERLAY_REGS 3
#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)

struct drm_i915_gem_phys_object {
	int id;
	struct page **page_list;
	drm_dma_handle_t *handle;
	struct drm_gem_object *cur_obj;
};

typedef struct _drm_i915_ring_buffer {
typedef struct _drm_i915_ring_buffer {
	int tail_mask;
	int tail_mask;
	unsigned long Size;
	unsigned long Size;
@@ -358,6 +370,9 @@ typedef struct drm_i915_private {
		uint32_t bit_6_swizzle_x;
		uint32_t bit_6_swizzle_x;
		/** Bit 6 swizzling required for Y tiling */
		/** Bit 6 swizzling required for Y tiling */
		uint32_t bit_6_swizzle_y;
		uint32_t bit_6_swizzle_y;

		/* storage for physical objects */
		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
	} mm;
	} mm;
} drm_i915_private_t;
} drm_i915_private_t;


@@ -436,6 +451,9 @@ struct drm_i915_gem_object {
	/** User space pin count and filp owning the pin */
	/** User space pin count and filp owning the pin */
	uint32_t user_pin_count;
	uint32_t user_pin_count;
	struct drm_file *pin_filp;
	struct drm_file *pin_filp;

	/** for phy allocated objects */
	struct drm_i915_gem_phys_object *phys_obj;
};
};


/**
/**
@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
				      int write);
				      int write);
int i915_gem_attach_phys_object(struct drm_device *dev,
				struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,
				 struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);


/* i915_gem_tiling.c */
/* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
+187 −2
Original line number Original line Diff line number Diff line
@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_evict_something(struct drm_device *dev);
static int i915_gem_evict_something(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
				struct drm_i915_gem_pwrite *args,
				struct drm_file *file_priv);


int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
		     unsigned long end)
		     unsigned long end)
@@ -386,7 +389,9 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
	 * pread/pwrite currently are reading and writing from the CPU
	 * pread/pwrite currently are reading and writing from the CPU
	 * perspective, requiring manual detiling by the client.
	 * perspective, requiring manual detiling by the client.
	 */
	 */
	if (obj_priv->tiling_mode == I915_TILING_NONE &&
	if (obj_priv->phys_obj)
		ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
	else if (obj_priv->tiling_mode == I915_TILING_NONE &&
		 dev->gtt_total != 0)
		 dev->gtt_total != 0)
		ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
		ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
	else
	else
@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
	while (obj_priv->pin_count > 0)
	while (obj_priv->pin_count > 0)
		i915_gem_object_unpin(obj);
		i915_gem_object_unpin(obj);


	if (obj_priv->phys_obj)
		i915_gem_detach_phys_object(dev, obj);

	i915_gem_object_unbind(obj);
	i915_gem_object_unbind(obj);


	list = &obj->map_list;
	list = &obj->map_list;
@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev)


	i915_gem_detect_bit_6_swizzle(dev);
	i915_gem_detect_bit_6_swizzle(dev);
}
}

/*
 * Create a physically contiguous memory object for this object
 * e.g. for cursor + overlay regs
 */
int i915_gem_init_phys_object(struct drm_device *dev,
			      int id, int size)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct drm_i915_gem_phys_object *phys_obj;
	int ret;

	if (dev_priv->mm.phys_objs[id - 1] || !size)
		return 0;

	phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
	if (!phys_obj)
		return -ENOMEM;

	phys_obj->id = id;

	phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
	if (!phys_obj->handle) {
		ret = -ENOMEM;
		goto kfree_obj;
	}
#ifdef CONFIG_X86
	set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif

	dev_priv->mm.phys_objs[id - 1] = phys_obj;

	return 0;
kfree_obj:
	drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
	return ret;
}

void i915_gem_free_phys_object(struct drm_device *dev, int id)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct drm_i915_gem_phys_object *phys_obj;

	if (!dev_priv->mm.phys_objs[id - 1])
		return;

	phys_obj = dev_priv->mm.phys_objs[id - 1];
	if (phys_obj->cur_obj) {
		i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
	}

#ifdef CONFIG_X86
	set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
	drm_pci_free(dev, phys_obj->handle);
	kfree(phys_obj);
	dev_priv->mm.phys_objs[id - 1] = NULL;
}

void i915_gem_free_all_phys_object(struct drm_device *dev)
{
	int i;

	for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
		i915_gem_free_phys_object(dev, i);
}

void i915_gem_detach_phys_object(struct drm_device *dev,
				 struct drm_gem_object *obj)
{
	struct drm_i915_gem_object *obj_priv;
	int i;
	int ret;
	int page_count;

	obj_priv = obj->driver_private;
	if (!obj_priv->phys_obj)
		return;

	ret = i915_gem_object_get_page_list(obj);
	if (ret)
		goto out;

	page_count = obj->size / PAGE_SIZE;

	for (i = 0; i < page_count; i++) {
		char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
		char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);

		memcpy(dst, src, PAGE_SIZE);
		kunmap_atomic(dst, KM_USER0);
	}
	drm_clflush_pages(obj_priv->page_list, page_count);
	drm_agp_chipset_flush(dev);
out:
	obj_priv->phys_obj->cur_obj = NULL;
	obj_priv->phys_obj = NULL;
}

int
i915_gem_attach_phys_object(struct drm_device *dev,
			    struct drm_gem_object *obj, int id)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	struct drm_i915_gem_object *obj_priv;
	int ret = 0;
	int page_count;
	int i;

	if (id > I915_MAX_PHYS_OBJECT)
		return -EINVAL;

	obj_priv = obj->driver_private;

	if (obj_priv->phys_obj) {
		if (obj_priv->phys_obj->id == id)
			return 0;
		i915_gem_detach_phys_object(dev, obj);
	}


	/* create a new object */
	if (!dev_priv->mm.phys_objs[id - 1]) {
		ret = i915_gem_init_phys_object(dev, id,
						obj->size);
		if (ret) {
			DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
			goto out;
		}
	}

	/* bind to the object */
	obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
	obj_priv->phys_obj->cur_obj = obj;

	ret = i915_gem_object_get_page_list(obj);
	if (ret) {
		DRM_ERROR("failed to get page list\n");
		goto out;
	}

	page_count = obj->size / PAGE_SIZE;

	for (i = 0; i < page_count; i++) {
		char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
		char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);

		memcpy(dst, src, PAGE_SIZE);
		kunmap_atomic(src, KM_USER0);
	}

	return 0;
out:
	return ret;
}

static int
i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
		     struct drm_i915_gem_pwrite *args,
		     struct drm_file *file_priv)
{
	struct drm_i915_gem_object *obj_priv = obj->driver_private;
	void *obj_addr;
	int ret;
	char __user *user_data;

	user_data = (char __user *) (uintptr_t) args->data_ptr;
	obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;

	DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
	ret = copy_from_user(obj_addr, user_data, args->size);
	if (ret)
		return -EFAULT;

	drm_agp_chipset_flush(dev);
	return 0;
}
Loading