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

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

Merge branch 'drm-intel-next' of git://git.freedesktop.org/git/drm-intel into drm-next

- fine-grained display power domains for byt (Imre)
- runtime pm prep patches for !hsw from Paulo
- WiZ hashing flag updates from Ville
- ppgtt setup cleanup and enabling of full 4G range on bdw (Ben)
- fixes from Jesse for the inherited intial config code
- gpu reset code improvements from Mika
- per-pipe num_planes refactoring from Damien
- stability fixes around bdw forcewake handling and other bdw w/a from Mika
  Ken
- and as usual a pile of smaller fixes all over

* 'drm-intel-next' of git://git.freedesktop.org/git/drm-intel: (107 commits)
  drm/i915: Go OCD on the Makefile
  drm/i915: Implement command buffer parsing logic
  drm/i915: Refactor shmem pread setup
  drm/i915: Avoid div by zero when pixel clock is large
  drm/i915: power domains: add vlv power wells
  drm/i915: factor out intel_set_cpu_fifo_underrun_reporting_nolock
  drm/i915: vlv: factor out valleyview_display_irq_install
  drm/i915: sanity check power well sw state against hw state
  drm/i915: factor out reset_vblank_counter
  drm/i915: sanitize PUNIT register macro definitions
  drm/i915: vlv: keep first level vblank IRQs masked
  drm/i915: check pipe power domain when reading its hw state
  drm/i915: check port power domain when reading the encoder hw state
  drm/i915: get port power domain in connector detect handlers
  drm/i915: add port power domains
  drm/i915: add noop power well handlers instead of NULL checking them
  drm/i915: split power well 'set' handler to separate enable/disable/sync_hw
  drm/i915: add init power domain to always-on power wells
  drm/i915: move power domain macros to intel_pm.c
  drm/i915: Disable full ppgtt by default
  ...
parents e40d6410 e19b9137
Loading
Loading
Loading
Loading
+46 −35
Original line number Diff line number Diff line
@@ -3,58 +3,69 @@
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.

ccflags-y := -Iinclude/drm
i915-y := i915_drv.o i915_dma.o i915_irq.o \
	  i915_gpu_error.o \

# Please keep these build lists sorted!

# core driver code
i915-y := i915_drv.o \
	  i915_params.o \
          i915_suspend.o \
	  i915_gem.o \
	  i915_sysfs.o \
	  intel_pm.o
i915-$(CONFIG_COMPAT)   += i915_ioc32.o
i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o

# GEM code
i915-y += i915_cmd_parser.o \
	  i915_gem_context.o \
	  i915_gem_debug.o \
	  i915_gem_dmabuf.o \
	  i915_gem_evict.o \
	  i915_gem_execbuffer.o \
	  i915_gem_gtt.o \
	  i915_gem.o \
	  i915_gem_stolen.o \
	  i915_gem_tiling.o \
	  i915_params.o \
	  i915_sysfs.o \
	  i915_gpu_error.o \
	  i915_irq.o \
	  i915_trace_points.o \
	  i915_ums.o \
	  intel_ringbuffer.o \
	  intel_uncore.o

# modesetting core code
i915-y += intel_bios.o \
	  intel_display.o \
	  intel_crt.o \
	  intel_lvds.o \
	  intel_dsi.o \
	  intel_dsi_cmd.o \
	  intel_dsi_pll.o \
	  intel_bios.o \
	  intel_ddi.o \
	  intel_dp.o \
	  intel_hdmi.o \
	  intel_sdvo.o \
	  intel_modes.o \
	  intel_panel.o \
	  intel_pm.o \
	  intel_i2c.o \
	  intel_tv.o \
	  intel_dvo.o \
	  intel_ringbuffer.o \
	  intel_overlay.o \
	  intel_sprite.o \
	  intel_sideband.o \
	  intel_uncore.o \
	  intel_sprite.o
i915-$(CONFIG_ACPI)		+= intel_acpi.o intel_opregion.o
i915-$(CONFIG_DRM_I915_FBDEV)	+= intel_fbdev.o

# modesetting output/encoder code
i915-y += dvo_ch7017.o \
	  dvo_ch7xxx.o \
	  dvo_ch7017.o \
	  dvo_ivch.o \
	  dvo_tfp410.o \
	  dvo_sil164.o \
	  dvo_ns2501.o \
	  i915_gem_dmabuf.o

i915-$(CONFIG_COMPAT)   += i915_ioc32.o

i915-$(CONFIG_ACPI)	+= intel_acpi.o intel_opregion.o

i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o
	  dvo_sil164.o \
	  dvo_tfp410.o \
	  intel_crt.o \
	  intel_ddi.o \
	  intel_dp.o \
	  intel_dsi_cmd.o \
	  intel_dsi.o \
	  intel_dsi_pll.o \
	  intel_dvo.o \
	  intel_hdmi.o \
	  intel_i2c.o \
	  intel_lvds.o \
	  intel_panel.o \
	  intel_sdvo.o \
	  intel_tv.o

i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
# legacy horrors
i915-y += i915_dma.o \
	  i915_ums.o

obj-$(CONFIG_DRM_I915)  += i915.o

+485 −0
Original line number Diff line number Diff line
/*
 * Copyright © 2013 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Brad Volkin <bradley.d.volkin@intel.com>
 *
 */

#include "i915_drv.h"

/**
 * DOC: i915 batch buffer command parser
 *
 * Motivation:
 * Certain OpenGL features (e.g. transform feedback, performance monitoring)
 * require userspace code to submit batches containing commands such as
 * MI_LOAD_REGISTER_IMM to access various registers. Unfortunately, some
 * generations of the hardware will noop these commands in "unsecure" batches
 * (which includes all userspace batches submitted via i915) even though the
 * commands may be safe and represent the intended programming model of the
 * device.
 *
 * The software command parser is similar in operation to the command parsing
 * done in hardware for unsecure batches. However, the software parser allows
 * some operations that would be noop'd by hardware, if the parser determines
 * the operation is safe, and submits the batch as "secure" to prevent hardware
 * parsing.
 *
 * Threats:
 * At a high level, the hardware (and software) checks attempt to prevent
 * granting userspace undue privileges. There are three categories of privilege.
 *
 * First, commands which are explicitly defined as privileged or which should
 * only be used by the kernel driver. The parser generally rejects such
 * commands, though it may allow some from the drm master process.
 *
 * Second, commands which access registers. To support correct/enhanced
 * userspace functionality, particularly certain OpenGL extensions, the parser
 * provides a whitelist of registers which userspace may safely access (for both
 * normal and drm master processes).
 *
 * Third, commands which access privileged memory (i.e. GGTT, HWS page, etc).
 * The parser always rejects such commands.
 *
 * The majority of the problematic commands fall in the MI_* range, with only a
 * few specific commands on each ring (e.g. PIPE_CONTROL and MI_FLUSH_DW).
 *
 * Implementation:
 * Each ring maintains tables of commands and registers which the parser uses in
 * scanning batch buffers submitted to that ring.
 *
 * Since the set of commands that the parser must check for is significantly
 * smaller than the number of commands supported, the parser tables contain only
 * those commands required by the parser. This generally works because command
 * opcode ranges have standard command length encodings. So for commands that
 * the parser does not need to check, it can easily skip them. This is
 * implementated via a per-ring length decoding vfunc.
 *
 * Unfortunately, there are a number of commands that do not follow the standard
 * length encoding for their opcode range, primarily amongst the MI_* commands.
 * To handle this, the parser provides a way to define explicit "skip" entries
 * in the per-ring command tables.
 *
 * Other command table entries map fairly directly to high level categories
 * mentioned above: rejected, master-only, register whitelist. The parser
 * implements a number of checks, including the privileged memory checks, via a
 * general bitmasking mechanism.
 */

static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
{
	u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
	u32 subclient =
		(cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;

	if (client == INSTR_MI_CLIENT)
		return 0x3F;
	else if (client == INSTR_RC_CLIENT) {
		if (subclient == INSTR_MEDIA_SUBCLIENT)
			return 0xFFFF;
		else
			return 0xFF;
	}

	DRM_DEBUG_DRIVER("CMD: Abnormal rcs cmd length! 0x%08X\n", cmd_header);
	return 0;
}

static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
{
	u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
	u32 subclient =
		(cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;

	if (client == INSTR_MI_CLIENT)
		return 0x3F;
	else if (client == INSTR_RC_CLIENT) {
		if (subclient == INSTR_MEDIA_SUBCLIENT)
			return 0xFFF;
		else
			return 0xFF;
	}

	DRM_DEBUG_DRIVER("CMD: Abnormal bsd cmd length! 0x%08X\n", cmd_header);
	return 0;
}

static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
{
	u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;

	if (client == INSTR_MI_CLIENT)
		return 0x3F;
	else if (client == INSTR_BC_CLIENT)
		return 0xFF;

	DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header);
	return 0;
}

static void validate_cmds_sorted(struct intel_ring_buffer *ring)
{
	int i;

	if (!ring->cmd_tables || ring->cmd_table_count == 0)
		return;

	for (i = 0; i < ring->cmd_table_count; i++) {
		const struct drm_i915_cmd_table *table = &ring->cmd_tables[i];
		u32 previous = 0;
		int j;

		for (j = 0; j < table->count; j++) {
			const struct drm_i915_cmd_descriptor *desc =
				&table->table[i];
			u32 curr = desc->cmd.value & desc->cmd.mask;

			if (curr < previous)
				DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n",
					  ring->id, i, j, curr, previous);

			previous = curr;
		}
	}
}

static void check_sorted(int ring_id, const u32 *reg_table, int reg_count)
{
	int i;
	u32 previous = 0;

	for (i = 0; i < reg_count; i++) {
		u32 curr = reg_table[i];

		if (curr < previous)
			DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
				  ring_id, i, curr, previous);

		previous = curr;
	}
}

static void validate_regs_sorted(struct intel_ring_buffer *ring)
{
	check_sorted(ring->id, ring->reg_table, ring->reg_count);
	check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count);
}

/**
 * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer
 * @ring: the ringbuffer to initialize
 *
 * Optionally initializes fields related to batch buffer command parsing in the
 * struct intel_ring_buffer based on whether the platform requires software
 * command parsing.
 */
void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
{
	if (!IS_GEN7(ring->dev))
		return;

	switch (ring->id) {
	case RCS:
		ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
		break;
	case VCS:
		ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
		break;
	case BCS:
		ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
		break;
	case VECS:
		/* VECS can use the same length_mask function as VCS */
		ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
		break;
	default:
		DRM_ERROR("CMD: cmd_parser_init with unknown ring: %d\n",
			  ring->id);
		BUG();
	}

	validate_cmds_sorted(ring);
	validate_regs_sorted(ring);
}

static const struct drm_i915_cmd_descriptor*
find_cmd_in_table(const struct drm_i915_cmd_table *table,
		  u32 cmd_header)
{
	int i;

	for (i = 0; i < table->count; i++) {
		const struct drm_i915_cmd_descriptor *desc = &table->table[i];
		u32 masked_cmd = desc->cmd.mask & cmd_header;
		u32 masked_value = desc->cmd.value & desc->cmd.mask;

		if (masked_cmd == masked_value)
			return desc;
	}

	return NULL;
}

/*
 * Returns a pointer to a descriptor for the command specified by cmd_header.
 *
 * The caller must supply space for a default descriptor via the default_desc
 * parameter. If no descriptor for the specified command exists in the ring's
 * command parser tables, this function fills in default_desc based on the
 * ring's default length encoding and returns default_desc.
 */
static const struct drm_i915_cmd_descriptor*
find_cmd(struct intel_ring_buffer *ring,
	 u32 cmd_header,
	 struct drm_i915_cmd_descriptor *default_desc)
{
	u32 mask;
	int i;

	for (i = 0; i < ring->cmd_table_count; i++) {
		const struct drm_i915_cmd_descriptor *desc;

		desc = find_cmd_in_table(&ring->cmd_tables[i], cmd_header);
		if (desc)
			return desc;
	}

	mask = ring->get_cmd_length_mask(cmd_header);
	if (!mask)
		return NULL;

	BUG_ON(!default_desc);
	default_desc->flags = CMD_DESC_SKIP;
	default_desc->length.mask = mask;

	return default_desc;
}

static bool valid_reg(const u32 *table, int count, u32 addr)
{
	if (table && count != 0) {
		int i;

		for (i = 0; i < count; i++) {
			if (table[i] == addr)
				return true;
		}
	}

	return false;
}

static u32 *vmap_batch(struct drm_i915_gem_object *obj)
{
	int i;
	void *addr = NULL;
	struct sg_page_iter sg_iter;
	struct page **pages;

	pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
	if (pages == NULL) {
		DRM_DEBUG_DRIVER("Failed to get space for pages\n");
		goto finish;
	}

	i = 0;
	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
		pages[i] = sg_page_iter_page(&sg_iter);
		i++;
	}

	addr = vmap(pages, i, 0, PAGE_KERNEL);
	if (addr == NULL) {
		DRM_DEBUG_DRIVER("Failed to vmap pages\n");
		goto finish;
	}

finish:
	if (pages)
		drm_free_large(pages);
	return (u32*)addr;
}

/**
 * i915_needs_cmd_parser() - should a given ring use software command parsing?
 * @ring: the ring in question
 *
 * Only certain platforms require software batch buffer command parsing, and
 * only when enabled via module paramter.
 *
 * Return: true if the ring requires software command parsing
 */
bool i915_needs_cmd_parser(struct intel_ring_buffer *ring)
{
	/* No command tables indicates a platform without parsing */
	if (!ring->cmd_tables)
		return false;

	return (i915.enable_cmd_parser == 1);
}

#define LENGTH_BIAS 2

/**
 * i915_parse_cmds() - parse a submitted batch buffer for privilege violations
 * @ring: the ring on which the batch is to execute
 * @batch_obj: the batch buffer in question
 * @batch_start_offset: byte offset in the batch at which execution starts
 * @is_master: is the submitting process the drm master?
 *
 * Parses the specified batch buffer looking for privilege violations as
 * described in the overview.
 *
 * Return: non-zero if the parser finds violations or otherwise fails
 */
int i915_parse_cmds(struct intel_ring_buffer *ring,
		    struct drm_i915_gem_object *batch_obj,
		    u32 batch_start_offset,
		    bool is_master)
{
	int ret = 0;
	u32 *cmd, *batch_base, *batch_end;
	struct drm_i915_cmd_descriptor default_desc = { 0 };
	int needs_clflush = 0;

	ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush);
	if (ret) {
		DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
		return ret;
	}

	batch_base = vmap_batch(batch_obj);
	if (!batch_base) {
		DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
		i915_gem_object_unpin_pages(batch_obj);
		return -ENOMEM;
	}

	if (needs_clflush)
		drm_clflush_virt_range((char *)batch_base, batch_obj->base.size);

	cmd = batch_base + (batch_start_offset / sizeof(*cmd));
	batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));

	while (cmd < batch_end) {
		const struct drm_i915_cmd_descriptor *desc;
		u32 length;

		if (*cmd == MI_BATCH_BUFFER_END)
			break;

		desc = find_cmd(ring, *cmd, &default_desc);
		if (!desc) {
			DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n",
					 *cmd);
			ret = -EINVAL;
			break;
		}

		if (desc->flags & CMD_DESC_FIXED)
			length = desc->length.fixed;
		else
			length = ((*cmd & desc->length.mask) + LENGTH_BIAS);

		if ((batch_end - cmd) < length) {
			DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%ld\n",
					 *cmd,
					 length,
					 batch_end - cmd);
			ret = -EINVAL;
			break;
		}

		if (desc->flags & CMD_DESC_REJECT) {
			DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd);
			ret = -EINVAL;
			break;
		}

		if ((desc->flags & CMD_DESC_MASTER) && !is_master) {
			DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n",
					 *cmd);
			ret = -EINVAL;
			break;
		}

		if (desc->flags & CMD_DESC_REGISTER) {
			u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask;

			if (!valid_reg(ring->reg_table,
				       ring->reg_count, reg_addr)) {
				if (!is_master ||
				    !valid_reg(ring->master_reg_table,
					       ring->master_reg_count,
					       reg_addr)) {
					DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
							 reg_addr,
							 *cmd,
							 ring->id);
					ret = -EINVAL;
					break;
				}
			}
		}

		if (desc->flags & CMD_DESC_BITMASK) {
			int i;

			for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) {
				u32 dword;

				if (desc->bits[i].mask == 0)
					break;

				dword = cmd[desc->bits[i].offset] &
					desc->bits[i].mask;

				if (dword != desc->bits[i].expected) {
					DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n",
							 *cmd,
							 desc->bits[i].mask,
							 desc->bits[i].expected,
							 dword, ring->id);
					ret = -EINVAL;
					break;
				}
			}

			if (ret)
				break;
		}

		cmd += length;
	}

	if (cmd >= batch_end) {
		DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
		ret = -EINVAL;
	}

	vunmap(batch_base);

	i915_gem_object_unpin_pages(batch_obj);

	return ret;
}
+61 −18
Original line number Diff line number Diff line
@@ -602,7 +602,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
	intel_runtime_pm_get(dev_priv);

	if (INTEL_INFO(dev)->gen >= 8) {
		int i;
		seq_printf(m, "Master Interrupt Control:\t%08x\n",
			   I915_READ(GEN8_MASTER_IRQ));

@@ -615,16 +614,16 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
				   i, I915_READ(GEN8_GT_IER(i)));
		}

		for_each_pipe(i) {
		for_each_pipe(pipe) {
			seq_printf(m, "Pipe %c IMR:\t%08x\n",
				   pipe_name(i),
				   I915_READ(GEN8_DE_PIPE_IMR(i)));
				   pipe_name(pipe),
				   I915_READ(GEN8_DE_PIPE_IMR(pipe)));
			seq_printf(m, "Pipe %c IIR:\t%08x\n",
				   pipe_name(i),
				   I915_READ(GEN8_DE_PIPE_IIR(i)));
				   pipe_name(pipe),
				   I915_READ(GEN8_DE_PIPE_IIR(pipe)));
			seq_printf(m, "Pipe %c IER:\t%08x\n",
				   pipe_name(i),
				   I915_READ(GEN8_DE_PIPE_IER(i)));
				   pipe_name(pipe),
				   I915_READ(GEN8_DE_PIPE_IER(pipe)));
		}

		seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -1348,6 +1347,8 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
		return 0;
	}

	intel_runtime_pm_get(dev_priv);

	if (intel_fbc_enabled(dev)) {
		seq_puts(m, "FBC enabled\n");
	} else {
@@ -1391,6 +1392,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
		}
		seq_putc(m, '\n');
	}

	intel_runtime_pm_put(dev_priv);

	return 0;
}

@@ -1405,11 +1409,15 @@ static int i915_ips_status(struct seq_file *m, void *unused)
		return 0;
	}

	intel_runtime_pm_get(dev_priv);

	if (IS_BROADWELL(dev) || I915_READ(IPS_CTL) & IPS_ENABLE)
		seq_puts(m, "enabled\n");
	else
		seq_puts(m, "disabled\n");

	intel_runtime_pm_put(dev_priv);

	return 0;
}

@@ -1420,6 +1428,8 @@ static int i915_sr_status(struct seq_file *m, void *unused)
	drm_i915_private_t *dev_priv = dev->dev_private;
	bool sr_enabled = false;

	intel_runtime_pm_get(dev_priv);

	if (HAS_PCH_SPLIT(dev))
		sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
	else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
@@ -1429,6 +1439,8 @@ static int i915_sr_status(struct seq_file *m, void *unused)
	else if (IS_PINEVIEW(dev))
		sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;

	intel_runtime_pm_put(dev_priv);

	seq_printf(m, "self-refresh: %s\n",
		   sr_enabled ? "enabled" : "disabled");

@@ -1468,7 +1480,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
	struct drm_info_node *node = (struct drm_info_node *) m->private;
	struct drm_device *dev = node->minor->dev;
	drm_i915_private_t *dev_priv = dev->dev_private;
	int ret;
	int ret = 0;
	int gpu_freq, ia_freq;

	if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
@@ -1476,12 +1488,13 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
		return 0;
	}

	intel_runtime_pm_get(dev_priv);

	flush_delayed_work(&dev_priv->rps.delayed_resume_work);

	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
	if (ret)
		return ret;
	intel_runtime_pm_get(dev_priv);
		goto out;

	seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");

@@ -1498,10 +1511,11 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
			   ((ia_freq >> 8) & 0xff) * 100);
	}

	intel_runtime_pm_put(dev_priv);
	mutex_unlock(&dev_priv->rps.hw_lock);

	return 0;
out:
	intel_runtime_pm_put(dev_priv);
	return ret;
}

static int i915_gfxec(struct seq_file *m, void *unused)
@@ -1757,7 +1771,7 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
		return;

	seq_printf(m, "Page directories: %d\n", ppgtt->num_pd_pages);
	seq_printf(m, "Page tables: %d\n", ppgtt->num_pt_pages);
	seq_printf(m, "Page tables: %d\n", ppgtt->num_pd_entries);
	for_each_ring(ring, dev_priv, unused) {
		seq_printf(m, "%s\n", ring->name);
		for (i = 0; i < 4; i++) {
@@ -1972,12 +1986,16 @@ static int i915_energy_uJ(struct seq_file *m, void *data)
	if (INTEL_INFO(dev)->gen < 6)
		return -ENODEV;

	intel_runtime_pm_get(dev_priv);

	rdmsrl(MSR_RAPL_POWER_UNIT, power);
	power = (power & 0x1f00) >> 8;
	units = 1000000 / (1 << power); /* convert to uJ */
	power = I915_READ(MCH_SECP_NRG_STTS);
	power *= units;

	intel_runtime_pm_put(dev_priv);

	seq_printf(m, "%llu", (long long unsigned)power);

	return 0;
@@ -1997,7 +2015,7 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
	mutex_lock(&dev_priv->pc8.lock);
	seq_printf(m, "Requirements met: %s\n",
		   yesno(dev_priv->pc8.requirements_met));
	seq_printf(m, "GPU idle: %s\n", yesno(dev_priv->pc8.gpu_idle));
	seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy));
	seq_printf(m, "Disable count: %d\n", dev_priv->pc8.disable_count);
	seq_printf(m, "IRQs disabled: %s\n",
		   yesno(dev_priv->pc8.irqs_disabled));
@@ -2030,6 +2048,28 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
		return "TRANSCODER_C";
	case POWER_DOMAIN_TRANSCODER_EDP:
		return "TRANSCODER_EDP";
	case POWER_DOMAIN_PORT_DDI_A_2_LANES:
		return "PORT_DDI_A_2_LANES";
	case POWER_DOMAIN_PORT_DDI_A_4_LANES:
		return "PORT_DDI_A_4_LANES";
	case POWER_DOMAIN_PORT_DDI_B_2_LANES:
		return "PORT_DDI_B_2_LANES";
	case POWER_DOMAIN_PORT_DDI_B_4_LANES:
		return "PORT_DDI_B_4_LANES";
	case POWER_DOMAIN_PORT_DDI_C_2_LANES:
		return "PORT_DDI_C_2_LANES";
	case POWER_DOMAIN_PORT_DDI_C_4_LANES:
		return "PORT_DDI_C_4_LANES";
	case POWER_DOMAIN_PORT_DDI_D_2_LANES:
		return "PORT_DDI_D_2_LANES";
	case POWER_DOMAIN_PORT_DDI_D_4_LANES:
		return "PORT_DDI_D_4_LANES";
	case POWER_DOMAIN_PORT_DSI:
		return "PORT_DSI";
	case POWER_DOMAIN_PORT_CRT:
		return "PORT_CRT";
	case POWER_DOMAIN_PORT_OTHER:
		return "PORT_OTHER";
	case POWER_DOMAIN_VGA:
		return "VGA";
	case POWER_DOMAIN_AUDIO:
@@ -2180,6 +2220,7 @@ static void intel_connector_info(struct seq_file *m,
{
	struct intel_connector *intel_connector = to_intel_connector(connector);
	struct intel_encoder *intel_encoder = intel_connector->encoder;
	struct drm_display_mode *mode;

	seq_printf(m, "connector %d: type %s, status: %s\n",
		   connector->base.id, drm_get_connector_name(connector),
@@ -2202,6 +2243,9 @@ static void intel_connector_info(struct seq_file *m,
	else if (intel_encoder->type == INTEL_OUTPUT_LVDS)
		intel_lvds_info(m, intel_connector);

	seq_printf(m, "\tmodes:\n");
	list_for_each_entry(mode, &connector->modes, head)
		intel_seq_print_mode(m, 2, mode);
}

static int i915_display_info(struct seq_file *m, void *unused)
@@ -3167,9 +3211,8 @@ i915_wedged_set(void *data, u64 val)
{
	struct drm_device *dev = data;

	DRM_INFO("Manually setting wedged to %llu\n", val);
	i915_handle_error(dev, val);

	i915_handle_error(dev, val,
			  "Manually setting wedged to %llu", val);
	return 0;
}

+14 −10
Original line number Diff line number Diff line
@@ -1321,12 +1321,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
	if (ret)
		goto cleanup_vga_switcheroo;

	intel_power_domains_init_hw(dev_priv);

	ret = drm_irq_install(dev);
	if (ret)
		goto cleanup_gem_stolen;

	intel_power_domains_init_hw(dev);

	/* Important: The output setup functions called by modeset_init need
	 * working irqs for e.g. gmbus and dp aux transfers. */
	intel_modeset_init(dev);
@@ -1343,7 +1343,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
	/* FIXME: do pre/post-mode set stuff in core KMS code */
	dev->vblank_disable_allowed = true;
	if (INTEL_INFO(dev)->num_pipes == 0) {
		intel_display_power_put(dev, POWER_DOMAIN_VGA);
		intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
		return 0;
	}

@@ -1381,7 +1381,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
	WARN_ON(dev_priv->mm.aliasing_ppgtt);
	drm_mm_takedown(&dev_priv->gtt.base.mm);
cleanup_power:
	intel_display_power_put(dev, POWER_DOMAIN_VGA);
	intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
	drm_irq_uninstall(dev);
cleanup_gem_stolen:
	i915_gem_cleanup_stolen(dev);
@@ -1480,12 +1480,16 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_device_info *info;
	enum pipe pipe;

	info = (struct intel_device_info *)&dev_priv->info;

	info->num_sprites = 1;
	if (IS_VALLEYVIEW(dev))
		info->num_sprites = 2;
		for_each_pipe(pipe)
			info->num_sprites[pipe] = 2;
	else
		for_each_pipe(pipe)
			info->num_sprites[pipe] = 1;

	if (i915.disable_display) {
		DRM_INFO("Display disabled (module parameter)\n");
@@ -1702,7 +1706,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
			goto out_gem_unload;
	}

	intel_power_domains_init(dev);
	intel_power_domains_init(dev_priv);

	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
		ret = i915_load_modeset_init(dev);
@@ -1731,7 +1735,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
	return 0;

out_power_well:
	intel_power_domains_remove(dev);
	intel_power_domains_remove(dev_priv);
	drm_vblank_cleanup(dev);
out_gem_unload:
	if (dev_priv->mm.inactive_shrinker.scan_objects)
@@ -1781,8 +1785,8 @@ int i915_driver_unload(struct drm_device *dev)
	/* The i915.ko module is still not prepared to be loaded when
	 * the power well is not enabled, so just enable it in case
	 * we're going to unload/reload. */
	intel_display_set_init_power(dev, true);
	intel_power_domains_remove(dev);
	intel_display_set_init_power(dev_priv, true);
	intel_power_domains_remove(dev_priv);

	i915_teardown_sysfs(dev);

+11 −8
Original line number Diff line number Diff line
@@ -265,6 +265,7 @@ static const struct intel_device_info intel_broadwell_d_info = {
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
	.has_llc = 1,
	.has_ddi = 1,
	.has_fbc = 1,
	GEN_DEFAULT_PIPEOFFSETS,
};

@@ -274,6 +275,7 @@ static const struct intel_device_info intel_broadwell_m_info = {
	.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
	.has_llc = 1,
	.has_ddi = 1,
	.has_fbc = 1,
	GEN_DEFAULT_PIPEOFFSETS,
};

@@ -401,15 +403,13 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
	if (INTEL_INFO(dev)->gen < 6)
		return false;

	/* Until we get further testing... */
	if (IS_GEN8(dev)) {
		WARN_ON(!i915.preliminary_hw_support);
		return false;
	}

	if (i915.semaphores >= 0)
		return i915.semaphores;

	/* Until we get further testing... */
	if (IS_GEN8(dev))
		return false;

#ifdef CONFIG_INTEL_IOMMU
	/* Enable semaphores on SNB when IO remapping is off */
	if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
@@ -434,7 +434,7 @@ static int i915_drm_freeze(struct drm_device *dev)
	/* We do a lot of poking in a lot of registers, make sure they work
	 * properly. */
	hsw_disable_package_c8(dev_priv);
	intel_display_set_init_power(dev, true);
	intel_display_set_init_power(dev_priv, true);

	drm_kms_helper_poll_disable(dev);

@@ -477,6 +477,8 @@ static int i915_drm_freeze(struct drm_device *dev)
	intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
	console_unlock();

	dev_priv->suspend_count++;

	return 0;
}

@@ -556,7 +558,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
		mutex_unlock(&dev->struct_mutex);
	}

	intel_power_domains_init_hw(dev);
	intel_power_domains_init_hw(dev_priv);

	i915_restore_state(dev);
	intel_opregion_setup(dev);
@@ -847,6 +849,7 @@ static int i915_runtime_suspend(struct device *device)
	struct drm_i915_private *dev_priv = dev->dev_private;

	WARN_ON(!HAS_RUNTIME_PM(dev));
	assert_force_wake_inactive(dev_priv);

	DRM_DEBUG_KMS("Suspending device\n");

Loading