提交 e1dee197 编写于 作者: D Dave Airlie

Merge tag 'drm-intel-next-2015-04-23-fixed' of...

Merge tag 'drm-intel-next-2015-04-23-fixed' of git://anongit.freedesktop.org/drm-intel into drm-next

drm-intel-next-2015-04-23:
- dither support for ns2501 dvo (Thomas Richter)
- some polish for the gtt code and fixes to finally enable the cmd parser on hsw
- first pile of bxt stage 1 enabling (too many different people to list ...)
- more psr fixes from Rodrigo
- skl rotation support from Chandra
- more atomic work from Ander and Matt
- pile of cleanups and micro-ops for execlist from Chris
drm-intel-next-2015-04-10:
- cdclk handling cleanup and fixes from Ville
- more prep patches for olr removal from John Harrison
- gmbus pin naming rework from Jani (prep for bxt)
- remove ->new_config from Ander (more atomic conversion work)
- rps (boost) tuning and unification with byt/bsw from Chris
- cmd parser batch bool tuning from Chris
- gen8 dynamic pte allocation (Michel Thierry, based on work from Ben Widawsky)
- execlist tuning (not yet all of it) from Chris
- add drm_plane_from_index (Chandra)
- various small things all over

* tag 'drm-intel-next-2015-04-23-fixed' of git://anongit.freedesktop.org/drm-intel: (204 commits)
  drm/i915/gtt: Allocate va range only if vma is not bound
  drm/i915: Enable cmd parser to do secure batch promotion for aliasing ppgtt
  drm/i915: fix intel_prepare_ddi
  drm/i915: factor out ddi_get_encoder_port
  drm/i915/hdmi: check port in ibx_infoframe_enabled
  drm/i915/hdmi: fix vlv infoframe port check
  drm/i915: Silence compiler warning in dvo
  drm/i915: Update DRIVER_DATE to 20150423
  drm/i915: Enable dithering on NatSemi DVO2501 for Fujitsu S6010
  rm/i915: Move i915_get_ggtt_vma_pages into ggtt_bind_vma
  drm/i915: Don't try to outsmart gcc in i915_gem_gtt.c
  drm/i915: Unduplicate i915_ggtt_unbind/bind_vma
  drm/i915: Move ppgtt_bind/unbind around
  drm/i915: move i915_gem_restore_gtt_mappings around
  drm/i915: Fix up the vma aliasing ppgtt binding
  drm/i915: Remove misleading comment around bind_to_vm
  drm/i915: Don't use atomics for pg_dirty_rings
  drm/i915: Don't look at pg_dirty_rings for aliasing ppgtt
  drm/i915/skl: Support Y tiling in MMIO flips
  drm/i915: Fixup kerneldoc for struct intel_context
  ...

Conflicts:
	drivers/gpu/drm/i915/i915_drv.c
无相关合并请求
......@@ -4067,7 +4067,7 @@ int num_ioctls;</synopsis>
<title>DPIO</title>
!Pdrivers/gpu/drm/i915/i915_reg.h DPIO
<table id="dpiox2">
<title>Dual channel PHY (VLV/CHV)</title>
<title>Dual channel PHY (VLV/CHV/BXT)</title>
<tgroup cols="8">
<colspec colname="c0" />
<colspec colname="c1" />
......@@ -4118,7 +4118,7 @@ int num_ioctls;</synopsis>
</tgroup>
</table>
<table id="dpiox1">
<title>Single channel PHY (CHV)</title>
<title>Single channel PHY (CHV/BXT)</title>
<tgroup cols="4">
<colspec colname="c0" />
<colspec colname="c1" />
......
......@@ -546,6 +546,7 @@ static const struct pci_device_id intel_stolen_ids[] __initconst = {
INTEL_BDW_D_IDS(&gen8_stolen_funcs),
INTEL_CHV_IDS(&chv_stolen_funcs),
INTEL_SKL_IDS(&gen9_stolen_funcs),
INTEL_BXT_IDS(&gen9_stolen_funcs),
};
static void __init intel_graphics_stolen(int num, int slot, int func)
......
......@@ -1288,6 +1288,29 @@ unsigned int drm_plane_index(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_index);
/**
* drm_plane_from_index - find the registered plane at an index
* @dev: DRM device
* @idx: index of registered plane to find for
*
* Given a plane index, return the registered plane from DRM device's
* list of planes with matching index.
*/
struct drm_plane *
drm_plane_from_index(struct drm_device *dev, int idx)
{
struct drm_plane *plane;
unsigned int i = 0;
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
if (i == idx)
return plane;
i++;
}
return NULL;
}
EXPORT_SYMBOL(drm_plane_from_index);
/**
* drm_plane_force_disable - Forcibly disable a plane
* @plane: plane to disable
......
......@@ -23,6 +23,9 @@
* Authors:
* Eric Anholt <eric@anholt.net>
*
* Minor modifications (Dithering enable):
* Thomas Richter <thor@math.tu-berlin.de>
*
*/
#include "dvo.h"
......@@ -59,6 +62,8 @@
# define VR01_DVO_BYPASS_ENABLE (1 << 1)
/** Enables the DVO clock */
# define VR01_DVO_ENABLE (1 << 0)
/** Enable dithering for 18bpp panels. Not documented. */
# define VR01_DITHER_ENABLE (1 << 4)
/*
* LCD Interface Format
......@@ -74,6 +79,8 @@
# define VR10_INTERFACE_2X18 (2 << 2)
/** Enables 2x24-bit LVDS output */
# define VR10_INTERFACE_2X24 (3 << 2)
/** Mask that defines the depth of the pipeline */
# define VR10_INTERFACE_DEPTH_MASK (3 << 2)
/*
* VR20 LCD Horizontal Display Size
......@@ -342,9 +349,15 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
struct drm_display_mode *adjusted_mode)
{
uint16_t vr40 = 0;
uint16_t vr01;
uint16_t vr01 = 0;
uint16_t vr10;
ivch_read(dvo, VR10, &vr10);
/* Enable dithering for 18 bpp pipelines */
vr10 &= VR10_INTERFACE_DEPTH_MASK;
if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18)
vr01 = VR01_DITHER_ENABLE;
vr01 = 0;
vr40 = (VR40_STALL_ENABLE | VR40_VERTICAL_INTERP_ENABLE |
VR40_HORIZONTAL_INTERP_ENABLE);
......@@ -353,7 +366,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo,
uint16_t x_ratio, y_ratio;
vr01 |= VR01_PANEL_FIT_ENABLE;
vr40 |= VR40_CLOCK_GATING_ENABLE;
vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_ENHANCED_PANEL_FITTING;
x_ratio = (((mode->hdisplay - 1) << 16) /
(adjusted_mode->hdisplay - 1)) >> 2;
y_ratio = (((mode->vdisplay - 1) << 16) /
......@@ -380,6 +393,8 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo)
DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
ivch_read(dvo, VR01, &val);
DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
ivch_read(dvo, VR10, &val);
DRM_DEBUG_KMS("VR10: 0x%04x\n", val);
ivch_read(dvo, VR30, &val);
DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
ivch_read(dvo, VR40, &val);
......
此差异已折叠。
......@@ -869,6 +869,9 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
batch_len + batch_start_offset > src_obj->base.size)
return ERR_PTR(-E2BIG);
if (WARN_ON(dest_obj->pages_pin_count == 0))
return ERR_PTR(-ENODEV);
ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
if (ret) {
DRM_DEBUG_DRIVER("CMD: failed to prepare shadow batch\n");
......@@ -882,13 +885,6 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
goto unpin_src;
}
ret = i915_gem_object_get_pages(dest_obj);
if (ret) {
DRM_DEBUG_DRIVER("CMD: Failed to get pages for shadow batch\n");
goto unmap_src;
}
i915_gem_object_pin_pages(dest_obj);
ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
if (ret) {
DRM_DEBUG_DRIVER("CMD: Failed to set shadow batch to CPU\n");
......@@ -898,7 +894,6 @@ static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
dst = vmap_batch(dest_obj, 0, batch_len);
if (!dst) {
DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
i915_gem_object_unpin_pages(dest_obj);
ret = -ENOMEM;
goto unmap_src;
}
......@@ -1129,7 +1124,6 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
}
vunmap(batch_base);
i915_gem_object_unpin_pages(shadow_batch_obj);
return ret;
}
......
......@@ -96,7 +96,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
static const char *get_pin_flag(struct drm_i915_gem_object *obj)
{
if (i915_gem_obj_is_pinned(obj))
if (obj->pin_display)
return "p";
else
return " ";
......@@ -123,8 +123,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
struct i915_vma *vma;
int pin_count = 0;
seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %x %x %x%s%s%s",
seq_printf(m, "%pK: %s%s%s%s %8zdKiB %02x %02x %x %x %x%s%s%s",
&obj->base,
obj->active ? "*" : " ",
get_pin_flag(obj),
get_tiling_flag(obj),
get_global_flag(obj),
......@@ -159,9 +160,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
}
if (obj->stolen)
seq_printf(m, " (stolen: %08llx)", obj->stolen->start);
if (obj->pin_mappable || obj->fault_mappable) {
if (obj->pin_display || obj->fault_mappable) {
char s[3], *t = s;
if (obj->pin_mappable)
if (obj->pin_display)
*t++ = 'p';
if (obj->fault_mappable)
*t++ = 'f';
......@@ -361,31 +362,39 @@ static int per_file_stats(int id, void *ptr, void *data)
return 0;
}
#define print_file_stats(m, name, stats) \
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \
name, \
stats.count, \
stats.total, \
stats.active, \
stats.inactive, \
stats.global, \
stats.shared, \
stats.unbound)
#define print_file_stats(m, name, stats) do { \
if (stats.count) \
seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \
name, \
stats.count, \
stats.total, \
stats.active, \
stats.inactive, \
stats.global, \
stats.shared, \
stats.unbound); \
} while (0)
static void print_batch_pool_stats(struct seq_file *m,
struct drm_i915_private *dev_priv)
{
struct drm_i915_gem_object *obj;
struct file_stats stats;
struct intel_engine_cs *ring;
int i, j;
memset(&stats, 0, sizeof(stats));
list_for_each_entry(obj,
&dev_priv->mm.batch_pool.cache_list,
batch_pool_list)
per_file_stats(0, obj, &stats);
for_each_ring(ring, dev_priv, i) {
for (j = 0; j < ARRAY_SIZE(ring->batch_pool.cache_list); j++) {
list_for_each_entry(obj,
&ring->batch_pool.cache_list[j],
batch_pool_link)
per_file_stats(0, obj, &stats);
}
}
print_file_stats(m, "batch pool", stats);
print_file_stats(m, "[k]batch pool", stats);
}
#define count_vmas(list, member) do { \
......@@ -449,7 +458,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
size += i915_gem_obj_ggtt_size(obj);
++count;
}
if (obj->pin_mappable) {
if (obj->pin_display) {
mappable_size += i915_gem_obj_ggtt_size(obj);
++mappable_count;
}
......@@ -471,8 +480,6 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
seq_putc(m, '\n');
print_batch_pool_stats(m, dev_priv);
seq_putc(m, '\n');
list_for_each_entry_reverse(file, &dev->filelist, lhead) {
struct file_stats stats;
struct task_struct *task;
......@@ -613,24 +620,39 @@ static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
int count = 0;
int ret;
struct intel_engine_cs *ring;
int total = 0;
int ret, i, j;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
seq_puts(m, "cache:\n");
list_for_each_entry(obj,
&dev_priv->mm.batch_pool.cache_list,
batch_pool_list) {
seq_puts(m, " ");
describe_obj(m, obj);
seq_putc(m, '\n');
count++;
for_each_ring(ring, dev_priv, i) {
for (j = 0; j < ARRAY_SIZE(ring->batch_pool.cache_list); j++) {
int count;
count = 0;
list_for_each_entry(obj,
&ring->batch_pool.cache_list[j],
batch_pool_link)
count++;
seq_printf(m, "%s cache[%d]: %d objects\n",
ring->name, j, count);
list_for_each_entry(obj,
&ring->batch_pool.cache_list[j],
batch_pool_link) {
seq_puts(m, " ");
describe_obj(m, obj);
seq_putc(m, '\n');
}
total += count;
}
}
seq_printf(m, "total: %d\n", count);
seq_printf(m, "total: %d\n", total);
mutex_unlock(&dev->struct_mutex);
......@@ -643,31 +665,44 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring;
struct drm_i915_gem_request *gem_request;
int ret, count, i;
struct drm_i915_gem_request *rq;
int ret, any, i;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
count = 0;
any = 0;
for_each_ring(ring, dev_priv, i) {
if (list_empty(&ring->request_list))
int count;
count = 0;
list_for_each_entry(rq, &ring->request_list, list)
count++;
if (count == 0)
continue;
seq_printf(m, "%s requests:\n", ring->name);
list_for_each_entry(gem_request,
&ring->request_list,
list) {
seq_printf(m, " %x @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
seq_printf(m, "%s requests: %d\n", ring->name, count);
list_for_each_entry(rq, &ring->request_list, list) {
struct task_struct *task;
rcu_read_lock();
task = NULL;
if (rq->pid)
task = pid_task(rq->pid, PIDTYPE_PID);
seq_printf(m, " %x @ %d: %s [%d]\n",
rq->seqno,
(int) (jiffies - rq->emitted_jiffies),
task ? task->comm : "<unknown>",
task ? task->pid : -1);
rcu_read_unlock();
}
count++;
any++;
}
mutex_unlock(&dev->struct_mutex);
if (count == 0)
if (any == 0)
seq_puts(m, "No requests\n");
return 0;
......@@ -2153,8 +2188,6 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
if (!ppgtt)
return;
seq_printf(m, "Page directories: %d\n", ppgtt->num_pd_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++) {
......@@ -2226,6 +2259,44 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
return 0;
}
static int i915_rps_boost_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_file *file;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
if (ret)
goto unlock;
list_for_each_entry_reverse(file, &dev->filelist, lhead) {
struct drm_i915_file_private *file_priv = file->driver_priv;
struct task_struct *task;
rcu_read_lock();
task = pid_task(file->pid, PIDTYPE_PID);
seq_printf(m, "%s [%d]: %d boosts%s\n",
task ? task->comm : "<unknown>",
task ? task->pid : -1,
file_priv->rps_boosts,
list_empty(&file_priv->rps_boost) ? "" : ", active");
rcu_read_unlock();
}
seq_printf(m, "Kernel boosts: %d\n", dev_priv->rps.boosts);
mutex_unlock(&dev_priv->rps.hw_lock);
unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
static int i915_llc(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
......@@ -2287,9 +2358,6 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
}
seq_puts(m, "\n");
seq_printf(m, "Link standby: %s\n",
yesno((bool)dev_priv->psr.link_standby));
/* CHV PSR has no kind of performance counter */
if (HAS_DDI(dev)) {
psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
......@@ -4470,12 +4538,116 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_cache_sharing_fops,
i915_cache_sharing_get, i915_cache_sharing_set,
"%llu\n");
struct sseu_dev_status {
unsigned int slice_total;
unsigned int subslice_total;
unsigned int subslice_per_slice;
unsigned int eu_total;
unsigned int eu_per_subslice;
};
static void cherryview_sseu_device_status(struct drm_device *dev,
struct sseu_dev_status *stat)
{
struct drm_i915_private *dev_priv = dev->dev_private;
const int ss_max = 2;
int ss;
u32 sig1[ss_max], sig2[ss_max];
sig1[0] = I915_READ(CHV_POWER_SS0_SIG1);
sig1[1] = I915_READ(CHV_POWER_SS1_SIG1);
sig2[0] = I915_READ(CHV_POWER_SS0_SIG2);
sig2[1] = I915_READ(CHV_POWER_SS1_SIG2);
for (ss = 0; ss < ss_max; ss++) {
unsigned int eu_cnt;
if (sig1[ss] & CHV_SS_PG_ENABLE)
/* skip disabled subslice */
continue;
stat->slice_total = 1;
stat->subslice_per_slice++;
eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
stat->eu_total += eu_cnt;
stat->eu_per_subslice = max(stat->eu_per_subslice, eu_cnt);
}
stat->subslice_total = stat->subslice_per_slice;
}
static void gen9_sseu_device_status(struct drm_device *dev,
struct sseu_dev_status *stat)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int s_max = 3, ss_max = 4;
int s, ss;
u32 s_reg[s_max], eu_reg[2*s_max], eu_mask[2];
/* BXT has a single slice and at most 3 subslices. */
if (IS_BROXTON(dev)) {
s_max = 1;
ss_max = 3;
}
for (s = 0; s < s_max; s++) {
s_reg[s] = I915_READ(GEN9_SLICE_PGCTL_ACK(s));
eu_reg[2*s] = I915_READ(GEN9_SS01_EU_PGCTL_ACK(s));
eu_reg[2*s + 1] = I915_READ(GEN9_SS23_EU_PGCTL_ACK(s));
}
eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
GEN9_PGCTL_SSA_EU19_ACK |
GEN9_PGCTL_SSA_EU210_ACK |
GEN9_PGCTL_SSA_EU311_ACK;
eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
GEN9_PGCTL_SSB_EU19_ACK |
GEN9_PGCTL_SSB_EU210_ACK |
GEN9_PGCTL_SSB_EU311_ACK;
for (s = 0; s < s_max; s++) {
unsigned int ss_cnt = 0;
if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
/* skip disabled slice */
continue;
stat->slice_total++;
if (IS_SKYLAKE(dev))
ss_cnt = INTEL_INFO(dev)->subslice_per_slice;
for (ss = 0; ss < ss_max; ss++) {
unsigned int eu_cnt;
if (IS_BROXTON(dev) &&
!(s_reg[s] & (GEN9_PGCTL_SS_ACK(ss))))
/* skip disabled subslice */
continue;
if (IS_BROXTON(dev))
ss_cnt++;
eu_cnt = 2 * hweight32(eu_reg[2*s + ss/2] &
eu_mask[ss%2]);
stat->eu_total += eu_cnt;
stat->eu_per_subslice = max(stat->eu_per_subslice,
eu_cnt);
}
stat->subslice_total += ss_cnt;
stat->subslice_per_slice = max(stat->subslice_per_slice,
ss_cnt);
}
}
static int i915_sseu_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int s_tot = 0, ss_tot = 0, ss_per = 0, eu_tot = 0, eu_per = 0;
struct sseu_dev_status stat;
if ((INTEL_INFO(dev)->gen < 8) || IS_BROADWELL(dev))
return -ENODEV;
......@@ -4499,79 +4671,22 @@ static int i915_sseu_status(struct seq_file *m, void *unused)
yesno(INTEL_INFO(dev)->has_eu_pg));
seq_puts(m, "SSEU Device Status\n");
memset(&stat, 0, sizeof(stat));
if (IS_CHERRYVIEW(dev)) {
const int ss_max = 2;
int ss;
u32 sig1[ss_max], sig2[ss_max];
sig1[0] = I915_READ(CHV_POWER_SS0_SIG1);
sig1[1] = I915_READ(CHV_POWER_SS1_SIG1);
sig2[0] = I915_READ(CHV_POWER_SS0_SIG2);
sig2[1] = I915_READ(CHV_POWER_SS1_SIG2);
for (ss = 0; ss < ss_max; ss++) {
unsigned int eu_cnt;
if (sig1[ss] & CHV_SS_PG_ENABLE)
/* skip disabled subslice */
continue;
s_tot = 1;
ss_per++;
eu_cnt = ((sig1[ss] & CHV_EU08_PG_ENABLE) ? 0 : 2) +
((sig1[ss] & CHV_EU19_PG_ENABLE) ? 0 : 2) +
((sig1[ss] & CHV_EU210_PG_ENABLE) ? 0 : 2) +
((sig2[ss] & CHV_EU311_PG_ENABLE) ? 0 : 2);
eu_tot += eu_cnt;
eu_per = max(eu_per, eu_cnt);
}
ss_tot = ss_per;
} else if (IS_SKYLAKE(dev)) {
const int s_max = 3, ss_max = 4;
int s, ss;
u32 s_reg[s_max], eu_reg[2*s_max], eu_mask[2];
s_reg[0] = I915_READ(GEN9_SLICE0_PGCTL_ACK);
s_reg[1] = I915_READ(GEN9_SLICE1_PGCTL_ACK);
s_reg[2] = I915_READ(GEN9_SLICE2_PGCTL_ACK);
eu_reg[0] = I915_READ(GEN9_SLICE0_SS01_EU_PGCTL_ACK);
eu_reg[1] = I915_READ(GEN9_SLICE0_SS23_EU_PGCTL_ACK);
eu_reg[2] = I915_READ(GEN9_SLICE1_SS01_EU_PGCTL_ACK);
eu_reg[3] = I915_READ(GEN9_SLICE1_SS23_EU_PGCTL_ACK);
eu_reg[4] = I915_READ(GEN9_SLICE2_SS01_EU_PGCTL_ACK);
eu_reg[5] = I915_READ(GEN9_SLICE2_SS23_EU_PGCTL_ACK);
eu_mask[0] = GEN9_PGCTL_SSA_EU08_ACK |
GEN9_PGCTL_SSA_EU19_ACK |
GEN9_PGCTL_SSA_EU210_ACK |
GEN9_PGCTL_SSA_EU311_ACK;
eu_mask[1] = GEN9_PGCTL_SSB_EU08_ACK |
GEN9_PGCTL_SSB_EU19_ACK |
GEN9_PGCTL_SSB_EU210_ACK |
GEN9_PGCTL_SSB_EU311_ACK;
for (s = 0; s < s_max; s++) {
if ((s_reg[s] & GEN9_PGCTL_SLICE_ACK) == 0)
/* skip disabled slice */
continue;
s_tot++;
ss_per = INTEL_INFO(dev)->subslice_per_slice;
ss_tot += ss_per;
for (ss = 0; ss < ss_max; ss++) {
unsigned int eu_cnt;
eu_cnt = 2 * hweight32(eu_reg[2*s + ss/2] &
eu_mask[ss%2]);
eu_tot += eu_cnt;
eu_per = max(eu_per, eu_cnt);
}
}
cherryview_sseu_device_status(dev, &stat);
} else if (INTEL_INFO(dev)->gen >= 9) {
gen9_sseu_device_status(dev, &stat);
}
seq_printf(m, " Enabled Slice Total: %u\n", s_tot);
seq_printf(m, " Enabled Subslice Total: %u\n", ss_tot);
seq_printf(m, " Enabled Subslice Per Slice: %u\n", ss_per);
seq_printf(m, " Enabled EU Total: %u\n", eu_tot);
seq_printf(m, " Enabled EU Per Subslice: %u\n", eu_per);
seq_printf(m, " Enabled Slice Total: %u\n",
stat.slice_total);
seq_printf(m, " Enabled Subslice Total: %u\n",
stat.subslice_total);
seq_printf(m, " Enabled Subslice Per Slice: %u\n",
stat.subslice_per_slice);
seq_printf(m, " Enabled EU Total: %u\n",
stat.eu_total);
seq_printf(m, " Enabled EU Per Subslice: %u\n",
stat.eu_per_subslice);
return 0;
}
......@@ -4691,6 +4806,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_ddb_info", i915_ddb_info, 0},
{"i915_sseu_status", i915_sseu_status, 0},
{"i915_drrs_status", i915_drrs_status, 0},
{"i915_rps_boost_info", i915_rps_boost_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
......@@ -4780,3 +4896,99 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
drm_debugfs_remove_files(info_list, 1, minor);
}
}
struct dpcd_block {
/* DPCD dump start address. */
unsigned int offset;
/* DPCD dump end address, inclusive. If unset, .size will be used. */
unsigned int end;
/* DPCD dump size. Used if .end is unset. If unset, defaults to 1. */
size_t size;
/* Only valid for eDP. */
bool edp;
};
static const struct dpcd_block i915_dpcd_debug[] = {
{ .offset = DP_DPCD_REV, .size = DP_RECEIVER_CAP_SIZE },
{ .offset = DP_PSR_SUPPORT, .end = DP_PSR_CAPS },
{ .offset = DP_DOWNSTREAM_PORT_0, .size = 16 },
{ .offset = DP_LINK_BW_SET, .end = DP_EDP_CONFIGURATION_SET },
{ .offset = DP_SINK_COUNT, .end = DP_ADJUST_REQUEST_LANE2_3 },
{ .offset = DP_SET_POWER },
{ .offset = DP_EDP_DPCD_REV },
{ .offset = DP_EDP_GENERAL_CAP_1, .end = DP_EDP_GENERAL_CAP_3 },
{ .offset = DP_EDP_DISPLAY_CONTROL_REGISTER, .end = DP_EDP_BACKLIGHT_FREQ_CAP_MAX_LSB },
{ .offset = DP_EDP_DBC_MINIMUM_BRIGHTNESS_SET, .end = DP_EDP_DBC_MAXIMUM_BRIGHTNESS_SET },
};
static int i915_dpcd_show(struct seq_file *m, void *data)
{
struct drm_connector *connector = m->private;
struct intel_dp *intel_dp =
enc_to_intel_dp(&intel_attached_encoder(connector)->base);
uint8_t buf[16];
ssize_t err;
int i;
for (i = 0; i < ARRAY_SIZE(i915_dpcd_debug); i++) {
const struct dpcd_block *b = &i915_dpcd_debug[i];
size_t size = b->end ? b->end - b->offset + 1 : (b->size ?: 1);
if (b->edp &&
connector->connector_type != DRM_MODE_CONNECTOR_eDP)
continue;
/* low tech for now */
if (WARN_ON(size > sizeof(buf)))
continue;
err = drm_dp_dpcd_read(&intel_dp->aux, b->offset, buf, size);
if (err <= 0) {
DRM_ERROR("dpcd read (%zu bytes at %u) failed (%zd)\n",
size, b->offset, err);
continue;
}
seq_printf(m, "%04x: %*ph\n", b->offset, (int) size, buf);
}
return 0;
}
static int i915_dpcd_open(struct inode *inode, struct file *file)
{
return single_open(file, i915_dpcd_show, inode->i_private);
}
static const struct file_operations i915_dpcd_fops = {
.owner = THIS_MODULE,
.open = i915_dpcd_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/**
* i915_debugfs_connector_add - add i915 specific connector debugfs files
* @connector: pointer to a registered drm_connector
*
* Cleanup will be done by drm_connector_unregister() through a call to
* drm_debugfs_connector_remove().
*
* Returns 0 on success, negative error codes on error.
*/
int i915_debugfs_connector_add(struct drm_connector *connector)
{
struct dentry *root = connector->debugfs_entry;
/* The connector must have been registered beforehands. */
if (!root)
return -ENODEV;
if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
connector->connector_type == DRM_MODE_CONNECTOR_eDP)
debugfs_create_file("i915_dpcd", S_IRUGO, root, connector,
&i915_dpcd_fops);
return 0;
}
......@@ -564,6 +564,140 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
#undef SEP_COMMA
}
static void cherryview_sseu_info_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_device_info *info;
u32 fuse, eu_dis;
info = (struct intel_device_info *)&dev_priv->info;
fuse = I915_READ(CHV_FUSE_GT);
info->slice_total = 1;
if (!(fuse & CHV_FGT_DISABLE_SS0)) {
info->subslice_per_slice++;
eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
CHV_FGT_EU_DIS_SS0_R1_MASK);
info->eu_total += 8 - hweight32(eu_dis);
}
if (!(fuse & CHV_FGT_DISABLE_SS1)) {
info->subslice_per_slice++;
eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
CHV_FGT_EU_DIS_SS1_R1_MASK);
info->eu_total += 8 - hweight32(eu_dis);
}
info->subslice_total = info->subslice_per_slice;
/*
* CHV expected to always have a uniform distribution of EU
* across subslices.
*/
info->eu_per_subslice = info->subslice_total ?
info->eu_total / info->subslice_total :
0;
/*
* CHV supports subslice power gating on devices with more than
* one subslice, and supports EU power gating on devices with
* more than one EU pair per subslice.
*/
info->has_slice_pg = 0;
info->has_subslice_pg = (info->subslice_total > 1);
info->has_eu_pg = (info->eu_per_subslice > 2);
}
static void gen9_sseu_info_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_device_info *info;
int s_max = 3, ss_max = 4, eu_max = 8;
int s, ss;
u32 fuse2, s_enable, ss_disable, eu_disable;
u8 eu_mask = 0xff;
/*
* BXT has a single slice. BXT also has at most 6 EU per subslice,
* and therefore only the lowest 6 bits of the 8-bit EU disable
* fields are valid.
*/
if (IS_BROXTON(dev)) {
s_max = 1;
eu_max = 6;
eu_mask = 0x3f;
}
info = (struct intel_device_info *)&dev_priv->info;
fuse2 = I915_READ(GEN8_FUSE2);
s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >>
GEN8_F2_S_ENA_SHIFT;
ss_disable = (fuse2 & GEN9_F2_SS_DIS_MASK) >>
GEN9_F2_SS_DIS_SHIFT;
info->slice_total = hweight32(s_enable);
/*
* The subslice disable field is global, i.e. it applies
* to each of the enabled slices.
*/
info->subslice_per_slice = ss_max - hweight32(ss_disable);
info->subslice_total = info->slice_total *
info->subslice_per_slice;
/*
* Iterate through enabled slices and subslices to
* count the total enabled EU.
*/
for (s = 0; s < s_max; s++) {
if (!(s_enable & (0x1 << s)))
/* skip disabled slice */
continue;
eu_disable = I915_READ(GEN9_EU_DISABLE(s));
for (ss = 0; ss < ss_max; ss++) {
int eu_per_ss;
if (ss_disable & (0x1 << ss))
/* skip disabled subslice */
continue;
eu_per_ss = eu_max - hweight8((eu_disable >> (ss*8)) &
eu_mask);
/*
* Record which subslice(s) has(have) 7 EUs. we
* can tune the hash used to spread work among
* subslices if they are unbalanced.
*/
if (eu_per_ss == 7)
info->subslice_7eu[s] |= 1 << ss;
info->eu_total += eu_per_ss;
}
}
/*
* SKL is expected to always have a uniform distribution
* of EU across subslices with the exception that any one
* EU in any one subslice may be fused off for die
* recovery. BXT is expected to be perfectly uniform in EU
* distribution.
*/
info->eu_per_subslice = info->subslice_total ?
DIV_ROUND_UP(info->eu_total,
info->subslice_total) : 0;
/*
* SKL supports slice power gating on devices with more than
* one slice, and supports EU power gating on devices with
* more than one EU pair per subslice. BXT supports subslice
* power gating on devices with more than one subslice, and
* supports EU power gating on devices with more than one EU
* pair per subslice.
*/
info->has_slice_pg = (IS_SKYLAKE(dev) && (info->slice_total > 1));
info->has_subslice_pg = (IS_BROXTON(dev) && (info->subslice_total > 1));
info->has_eu_pg = (info->eu_per_subslice > 2);
}
/*
* Determine various intel_device_info fields at runtime.
*
......@@ -585,7 +719,11 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
info = (struct intel_device_info *)&dev_priv->info;
if (IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen == 9)
if (IS_BROXTON(dev)) {
info->num_sprites[PIPE_A] = 3;
info->num_sprites[PIPE_B] = 3;
info->num_sprites[PIPE_C] = 2;
} else if (IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen == 9)
for_each_pipe(dev_priv, pipe)
info->num_sprites[pipe] = 2;
else
......@@ -620,116 +758,11 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
}
/* Initialize slice/subslice/EU info */
if (IS_CHERRYVIEW(dev)) {
u32 fuse, eu_dis;
fuse = I915_READ(CHV_FUSE_GT);
info->slice_total = 1;
if (!(fuse & CHV_FGT_DISABLE_SS0)) {
info->subslice_per_slice++;
eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
CHV_FGT_EU_DIS_SS0_R1_MASK);
info->eu_total += 8 - hweight32(eu_dis);
}
if (!(fuse & CHV_FGT_DISABLE_SS1)) {
info->subslice_per_slice++;
eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
CHV_FGT_EU_DIS_SS1_R1_MASK);
info->eu_total += 8 - hweight32(eu_dis);
}
info->subslice_total = info->subslice_per_slice;
/*
* CHV expected to always have a uniform distribution of EU
* across subslices.
*/
info->eu_per_subslice = info->subslice_total ?
info->eu_total / info->subslice_total :
0;
/*
* CHV supports subslice power gating on devices with more than
* one subslice, and supports EU power gating on devices with
* more than one EU pair per subslice.
*/
info->has_slice_pg = 0;
info->has_subslice_pg = (info->subslice_total > 1);
info->has_eu_pg = (info->eu_per_subslice > 2);
} else if (IS_SKYLAKE(dev)) {
const int s_max = 3, ss_max = 4, eu_max = 8;
int s, ss;
u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
fuse2 = I915_READ(GEN8_FUSE2);
s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >>
GEN8_F2_S_ENA_SHIFT;
ss_disable = (fuse2 & GEN9_F2_SS_DIS_MASK) >>
GEN9_F2_SS_DIS_SHIFT;
eu_disable[0] = I915_READ(GEN8_EU_DISABLE0);
eu_disable[1] = I915_READ(GEN8_EU_DISABLE1);
eu_disable[2] = I915_READ(GEN8_EU_DISABLE2);
info->slice_total = hweight32(s_enable);
/*
* The subslice disable field is global, i.e. it applies
* to each of the enabled slices.
*/
info->subslice_per_slice = ss_max - hweight32(ss_disable);
info->subslice_total = info->slice_total *
info->subslice_per_slice;
/*
* Iterate through enabled slices and subslices to
* count the total enabled EU.
*/
for (s = 0; s < s_max; s++) {
if (!(s_enable & (0x1 << s)))
/* skip disabled slice */
continue;
for (ss = 0; ss < ss_max; ss++) {
u32 n_disabled;
if (ss_disable & (0x1 << ss))
/* skip disabled subslice */
continue;
if (IS_CHERRYVIEW(dev))
cherryview_sseu_info_init(dev);
else if (INTEL_INFO(dev)->gen >= 9)
gen9_sseu_info_init(dev);
n_disabled = hweight8(eu_disable[s] >>
(ss * eu_max));
/*
* Record which subslice(s) has(have) 7 EUs. we
* can tune the hash used to spread work among
* subslices if they are unbalanced.
*/
if (eu_max - n_disabled == 7)
info->subslice_7eu[s] |= 1 << ss;
info->eu_total += eu_max - n_disabled;
}
}
/*
* SKL is expected to always have a uniform distribution
* of EU across subslices with the exception that any one
* EU in any one subslice may be fused off for die
* recovery.
*/
info->eu_per_subslice = info->subslice_total ?
DIV_ROUND_UP(info->eu_total,
info->subslice_total) : 0;
/*
* SKL supports slice power gating on devices with more than
* one slice, and supports EU power gating on devices with
* more than one EU pair per subslice.
*/
info->has_slice_pg = (info->slice_total > 1) ? 1 : 0;
info->has_subslice_pg = 0;
info->has_eu_pg = (info->eu_per_subslice > 2) ? 1 : 0;
}
DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
......@@ -1006,8 +1039,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
put_bridge:
pci_dev_put(dev_priv->bridge_dev);
free_priv:
if (dev_priv->slab)
kmem_cache_destroy(dev_priv->slab);
if (dev_priv->requests)
kmem_cache_destroy(dev_priv->requests);
if (dev_priv->vmas)
kmem_cache_destroy(dev_priv->vmas);
if (dev_priv->objects)
kmem_cache_destroy(dev_priv->objects);
kfree(dev_priv);
return ret;
}
......@@ -1072,7 +1109,6 @@ int i915_driver_unload(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_stolen(dev);
......@@ -1091,8 +1127,12 @@ int i915_driver_unload(struct drm_device *dev)
if (dev_priv->regs != NULL)
pci_iounmap(dev->pdev, dev_priv->regs);
if (dev_priv->slab)
kmem_cache_destroy(dev_priv->slab);
if (dev_priv->requests)
kmem_cache_destroy(dev_priv->requests);
if (dev_priv->vmas)
kmem_cache_destroy(dev_priv->vmas);
if (dev_priv->objects)
kmem_cache_destroy(dev_priv->objects);
pci_dev_put(dev_priv->bridge_dev);
kfree(dev_priv);
......
......@@ -381,6 +381,18 @@ static const struct intel_device_info intel_skylake_gt3_info = {
IVB_CURSOR_OFFSETS,
};
static const struct intel_device_info intel_broxton_info = {
.is_preliminary = 1,
.gen = 9,
.need_gfx_hws = 1, .has_hotplug = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
.num_pipes = 3,
.has_ddi = 1,
.has_fbc = 1,
GEN_DEFAULT_PIPEOFFSETS,
IVB_CURSOR_OFFSETS,
};
/*
* Make sure any device matches here are from most specific to most
* general. For example, since the Quanta match is based on the subsystem
......@@ -420,7 +432,8 @@ static const struct intel_device_info intel_skylake_gt3_info = {
INTEL_CHV_IDS(&intel_cherryview_info), \
INTEL_SKL_GT1_IDS(&intel_skylake_info), \
INTEL_SKL_GT2_IDS(&intel_skylake_info), \
INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info) \
INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info), \
INTEL_BXT_IDS(&intel_broxton_info)
static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_PCI_IDS,
......@@ -996,6 +1009,38 @@ static int hsw_suspend_complete(struct drm_i915_private *dev_priv)
return 0;
}
static int bxt_suspend_complete(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
/* TODO: when DC5 support is added disable DC5 here. */
broxton_ddi_phy_uninit(dev);
broxton_uninit_cdclk(dev);
bxt_enable_dc9(dev_priv);
return 0;
}
static int bxt_resume_prepare(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
/* TODO: when CSR FW support is added make sure the FW is loaded */
bxt_disable_dc9(dev_priv);
/*
* TODO: when DC5 support is added enable DC5 here if the CSR FW
* is available.
*/
broxton_init_cdclk(dev);
broxton_ddi_phy_init(dev);
intel_prepare_ddi(dev);
return 0;
}
/*
* Save all Gunit registers that may be lost after a D3 and a subsequent
* S0i[R123] transition. The list of registers needing a save/restore is
......@@ -1195,7 +1240,21 @@ int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on)
u32 val;
int err;
val = I915_READ(VLV_GTLC_SURVIVABILITY_REG);
#define COND (I915_READ(VLV_GTLC_SURVIVABILITY_REG) & VLV_GFX_CLK_STATUS_BIT)
/* Wait for a previous force-off to settle */
if (force_on && !IS_CHERRYVIEW(dev_priv->dev)) {
/* WARN_ON only for the Valleyview */
WARN_ON(!!(val & VLV_GFX_CLK_FORCE_ON_BIT) == force_on);
err = wait_for(!COND, 20);
if (err) {
DRM_ERROR("timeout waiting for GFX clock force-off (%08x)\n",
I915_READ(VLV_GTLC_SURVIVABILITY_REG));
return err;
}
}
val = I915_READ(VLV_GTLC_SURVIVABILITY_REG);
val &= ~VLV_GFX_CLK_FORCE_ON_BIT;
......@@ -1454,6 +1513,9 @@ static int intel_runtime_resume(struct device *device)
if (IS_GEN6(dev_priv))
intel_init_pch_refclk(dev);
if (IS_BROXTON(dev))
ret = bxt_resume_prepare(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_disable_pc8(dev_priv);
else if (IS_VALLEYVIEW(dev_priv))
......@@ -1486,7 +1548,9 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
int ret;
if (IS_HASWELL(dev) || IS_BROADWELL(dev))
if (IS_BROXTON(dev))
ret = bxt_suspend_complete(dev_priv);
else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
ret = hsw_suspend_complete(dev_priv);
else if (IS_VALLEYVIEW(dev))
ret = vlv_suspend_complete(dev_priv);
......
......@@ -56,7 +56,7 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20150327"
#define DRIVER_DATE "20150423"
#undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */
......@@ -130,7 +130,7 @@ enum transcoder {
*
* This value doesn't count the cursor plane.
*/
#define I915_MAX_PLANES 3
#define I915_MAX_PLANES 4
enum plane {
PLANE_A = 0,
......@@ -251,7 +251,6 @@ enum hpd_pin {
&dev->mode_config.connector_list, \
base.head)
#define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
if ((intel_encoder)->base.crtc == (__crtc))
......@@ -303,6 +302,9 @@ struct intel_dpll_hw_state {
uint32_t ctrl1;
/* HDMI only, 0 when used for DP */
uint32_t cfgcr1, cfgcr2;
/* bxt */
uint32_t ebb0, pll0, pll1, pll2, pll3, pll6, pll8, pcsdw12;
};
struct intel_shared_dpll_config {
......@@ -455,6 +457,7 @@ struct drm_i915_error_state {
u32 semaphore_seqno[I915_NUM_RINGS - 1];
/* Register state */
u32 start;
u32 tail;
u32 head;
u32 ctl;
......@@ -766,7 +769,7 @@ struct i915_ctx_hang_stats {
* context).
* @hang_stats: information about the role of this context in possible GPU
* hangs.
* @vm: virtual memory space used by this context.
* @ppgtt: virtual memory space used by this context.
* @legacy_hw_ctx: render context backing object and whether it is correctly
* initialized (legacy ring submission mechanism only).
* @link: link in the global list of contexts.
......@@ -880,7 +883,8 @@ struct i915_psr {
bool active;
struct delayed_work work;
unsigned busy_frontbuffer_bits;
bool link_standby;
bool psr2_support;
bool aux_frame_sync;
};
enum intel_pch {
......@@ -1034,11 +1038,16 @@ struct intel_gen6_power_mgmt {
u8 rp0_freq; /* Non-overclocked max frequency. */
u32 cz_freq;
u8 up_threshold; /* Current %busy required to uplock */
u8 down_threshold; /* Current %busy required to downclock */
int last_adj;
enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
bool enabled;
struct delayed_work delayed_resume_work;
struct list_head clients;
unsigned boosts;
/* manual wa residency calculations */
struct intel_rps_ei up_ei, down_ei;
......@@ -1136,11 +1145,6 @@ struct intel_l3_parity {
int which_slice;
};
struct i915_gem_batch_pool {
struct drm_device *dev;
struct list_head cache_list;
};
struct i915_gem_mm {
/** Memory allocator for GTT stolen memory */
struct drm_mm stolen;
......@@ -1154,13 +1158,6 @@ struct i915_gem_mm {
*/
struct list_head unbound_list;
/*
* A pool of objects to use as shadow copies of client batch buffers
* when the command parser is enabled. Prevents the client from
* modifying the batch contents after software parsing.
*/
struct i915_gem_batch_pool batch_pool;
/** Usable portion of the GTT for GEM */
unsigned long stolen_base; /* limited to low memory (32-bit) */
......@@ -1563,7 +1560,9 @@ struct i915_virtual_gpu {
struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *slab;
struct kmem_cache *objects;
struct kmem_cache *vmas;
struct kmem_cache *requests;
const struct intel_device_info info;
......@@ -1575,8 +1574,7 @@ struct drm_i915_private {
struct i915_virtual_gpu vgpu;
struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
struct intel_gmbus gmbus[GMBUS_NUM_PINS];
/** gmbus_mutex protects against concurrent usage of the single hw gmbus
* controller on different i2c buses. */
......@@ -1661,7 +1659,7 @@ struct drm_i915_private {
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
unsigned int fsb_freq, mem_freq, is_ddr3;
unsigned int vlv_cdclk_freq;
unsigned int cdclk_freq;
unsigned int hpll_freq;
/**
......@@ -1815,20 +1813,18 @@ struct drm_i915_private {
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
struct {
int (*do_execbuf)(struct drm_device *dev, struct drm_file *file,
struct intel_engine_cs *ring,
struct intel_context *ctx,
struct drm_i915_gem_execbuffer2 *args,
struct list_head *vmas,
struct drm_i915_gem_object *batch_obj,
u64 exec_start, u32 flags);
int (*execbuf_submit)(struct drm_device *dev, struct drm_file *file,
struct intel_engine_cs *ring,
struct intel_context *ctx,
struct drm_i915_gem_execbuffer2 *args,
struct list_head *vmas,
struct drm_i915_gem_object *batch_obj,
u64 exec_start, u32 flags);
int (*init_rings)(struct drm_device *dev);
void (*cleanup_ring)(struct intel_engine_cs *ring);
void (*stop_ring)(struct intel_engine_cs *ring);
} gt;
uint32_t request_uniq;
/*
* NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place.
......@@ -1917,7 +1913,7 @@ struct drm_i915_gem_object {
/** Used in execbuf to temporarily hold a ref */
struct list_head obj_exec_link;
struct list_head batch_pool_list;
struct list_head batch_pool_link;
/**
* This is set if the object is on the active lists (has pending
......@@ -1969,8 +1965,6 @@ struct drm_i915_gem_object {
* accurate mappable working set.
*/
unsigned int fault_mappable:1;
unsigned int pin_mappable:1;
unsigned int pin_display:1;
/*
* Is the object to be mapped as read-only to the GPU
......@@ -1984,8 +1978,14 @@ struct drm_i915_gem_object {
unsigned int frontbuffer_bits:INTEL_FRONTBUFFER_BITS;
unsigned int pin_display;
struct sg_table *pages;
int pages_pin_count;
struct get_page {
struct scatterlist *sg;
int last;
} get_page;
/* prime dma-buf support */
void *dma_buf_vmapping;
......@@ -2046,6 +2046,7 @@ struct drm_i915_gem_request {
struct kref ref;
/** On Which ring this request was generated */
struct drm_i915_private *i915;
struct intel_engine_cs *ring;
/** GEM sequence number associated with this request. */
......@@ -2093,8 +2094,6 @@ struct drm_i915_gem_request {
/** process identifier submitting this request */
struct pid *pid;
uint32_t uniq;
/**
* The ELSP only accepts two elements at a time, so we queue
* context/tail pairs on a given queue (ring->execlist_queue) until the
......@@ -2116,6 +2115,8 @@ struct drm_i915_gem_request {
};
int i915_gem_request_alloc(struct intel_engine_cs *ring,
struct intel_context *ctx);
void i915_gem_request_free(struct kref *req_ref);
static inline uint32_t
......@@ -2143,6 +2144,19 @@ i915_gem_request_unreference(struct drm_i915_gem_request *req)
kref_put(&req->ref, i915_gem_request_free);
}
static inline void
i915_gem_request_unreference__unlocked(struct drm_i915_gem_request *req)
{
struct drm_device *dev;
if (!req)
return;
dev = req->ring->dev;
if (kref_put_mutex(&req->ref, i915_gem_request_free, &dev->struct_mutex))
mutex_unlock(&dev->struct_mutex);
}
static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
struct drm_i915_gem_request *src)
{
......@@ -2168,12 +2182,13 @@ struct drm_i915_file_private {
struct {
spinlock_t lock;
struct list_head request_list;
struct delayed_work idle_work;
} mm;
struct idr context_idr;
atomic_t rps_wait_boost;
struct intel_engine_cs *bsd_ring;
struct list_head rps_boost;
struct intel_engine_cs *bsd_ring;
unsigned rps_boosts;
};
/*
......@@ -2307,6 +2322,7 @@ struct drm_i915_cmd_table {
#define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell)
#define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
#define IS_SKYLAKE(dev) (INTEL_INFO(dev)->is_skylake)
#define IS_BROXTON(dev) (!INTEL_INFO(dev)->is_skylake && IS_GEN9(dev))
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
#define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \
(INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
......@@ -2331,6 +2347,10 @@ struct drm_i915_cmd_table {
#define SKL_REVID_D0 (0x3)
#define SKL_REVID_E0 (0x4)
#define BXT_REVID_A0 (0x0)
#define BXT_REVID_B0 (0x3)
#define BXT_REVID_C0 (0x6)
/*
* The genX designation typically refers to the render engine, so render
* capability related checks should use IS_GEN, while display and other checks
......@@ -2520,6 +2540,13 @@ void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
enum forcewake_domains domains);
void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
enum forcewake_domains domains);
/* Like above but the caller must manage the uncore.lock itself.
* Must be used with I915_READ_FW and friends.
*/
void intel_uncore_forcewake_get__locked(struct drm_i915_private *dev_priv,
enum forcewake_domains domains);
void intel_uncore_forcewake_put__locked(struct drm_i915_private *dev_priv,
enum forcewake_domains domains);
void assert_forcewakes_inactive(struct drm_i915_private *dev_priv);
static inline bool intel_vgpu_active(struct drm_device *dev)
{
......@@ -2614,10 +2641,13 @@ void i915_init_vm(struct drm_i915_private *dev_priv,
void i915_gem_free_object(struct drm_gem_object *obj);
void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_MAPPABLE 0x1
#define PIN_NONBLOCK 0x2
#define PIN_GLOBAL 0x4
#define PIN_OFFSET_BIAS 0x8
/* Flags used by pin/bind&friends. */
#define PIN_MAPPABLE (1<<0)
#define PIN_NONBLOCK (1<<1)
#define PIN_GLOBAL (1<<2)
#define PIN_OFFSET_BIAS (1<<3)
#define PIN_USER (1<<4)
#define PIN_UPDATE (1<<5)
#define PIN_OFFSET_MASK (~4095)
int __must_check
i915_gem_object_pin(struct drm_i915_gem_object *obj,
......@@ -2641,15 +2671,32 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
int *needs_clflush);
int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
static inline int __sg_page_count(struct scatterlist *sg)
{
return sg->length >> PAGE_SHIFT;
}
static inline struct page *
i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
{
struct sg_page_iter sg_iter;
if (WARN_ON(n >= obj->base.size >> PAGE_SHIFT))
return NULL;
for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n)
return sg_page_iter_page(&sg_iter);
if (n < obj->get_page.last) {
obj->get_page.sg = obj->pages->sgl;
obj->get_page.last = 0;
}
while (obj->get_page.last + __sg_page_count(obj->get_page.sg) <= n) {
obj->get_page.last += __sg_page_count(obj->get_page.sg++);
if (unlikely(sg_is_chain(obj->get_page.sg)))
obj->get_page.sg = sg_chain_ptr(obj->get_page.sg);
}
return NULL;
return nth_page(sg_page(obj->get_page.sg), n - obj->get_page.last);
}
static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj)
{
BUG_ON(obj->pages == NULL);
......@@ -2993,8 +3040,10 @@ int i915_verify_lists(struct drm_device *dev);
int i915_debugfs_init(struct drm_minor *minor);
void i915_debugfs_cleanup(struct drm_minor *minor);
#ifdef CONFIG_DEBUG_FS
int i915_debugfs_connector_add(struct drm_connector *connector);
void intel_display_crc_init(struct drm_device *dev);
#else
static inline int i915_debugfs_connector_add(struct drm_connector *connector) {}
static inline void intel_display_crc_init(struct drm_device *dev) {}
#endif
......@@ -3021,13 +3070,6 @@ void i915_destroy_error_state(struct drm_device *dev);
void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
/* i915_gem_batch_pool.c */
void i915_gem_batch_pool_init(struct drm_device *dev,
struct i915_gem_batch_pool *pool);
void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
struct drm_i915_gem_object*
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
/* i915_cmd_parser.c */
int i915_cmd_parser_get_version(void);
int i915_cmd_parser_init_ring(struct intel_engine_cs *ring);
......@@ -3051,13 +3093,11 @@ void i915_teardown_sysfs(struct drm_device *dev_priv);
/* intel_i2c.c */
extern int intel_setup_gmbus(struct drm_device *dev);
extern void intel_teardown_gmbus(struct drm_device *dev);
static inline bool intel_gmbus_is_port_valid(unsigned port)
{
return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD);
}
extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
unsigned int pin);
extern struct i2c_adapter *intel_gmbus_get_adapter(
struct drm_i915_private *dev_priv, unsigned port);
extern struct i2c_adapter *
intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, unsigned int pin);
extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
......@@ -3203,6 +3243,17 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
#define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg)
#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
/* These are untraced mmio-accessors that are only valid to be used inside
* criticial sections inside IRQ handlers where forcewake is explicitly
* controlled.
* Think twice, and think again, before using these.
* Note: Should only be used between intel_uncore_forcewake_irqlock() and
* intel_uncore_forcewake_irqunlock().
*/
#define I915_READ_FW(reg__) readl(dev_priv->regs + (reg__))
#define I915_WRITE_FW(reg__, val__) writel(val__, dev_priv->regs + (reg__))
#define POSTING_READ_FW(reg__) (void)I915_READ_FW(reg__)
/* "Broadcast RGB" property */
#define INTEL_BROADCAST_RGB_AUTO 0
#define INTEL_BROADCAST_RGB_FULL 1
......
......@@ -378,13 +378,13 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj,
void *i915_gem_object_alloc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
return kmem_cache_zalloc(dev_priv->slab, GFP_KERNEL);
return kmem_cache_zalloc(dev_priv->objects, GFP_KERNEL);
}
void i915_gem_object_free(struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
kmem_cache_free(dev_priv->slab, obj);
kmem_cache_free(dev_priv->objects, obj);
}
static int
......@@ -1181,12 +1181,27 @@ static bool missed_irq(struct drm_i915_private *dev_priv,
return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings);
}
static bool can_wait_boost(struct drm_i915_file_private *file_priv)
static int __i915_spin_request(struct drm_i915_gem_request *rq)
{
if (file_priv == NULL)
return true;
unsigned long timeout;
if (i915_gem_request_get_ring(rq)->irq_refcount)
return -EBUSY;
timeout = jiffies + 1;
while (!need_resched()) {
if (i915_gem_request_completed(rq, true))
return 0;
if (time_after_eq(jiffies, timeout))
break;
return !atomic_xchg(&file_priv->rps_wait_boost, true);
cpu_relax_lowlatency();
}
if (i915_gem_request_completed(rq, false))
return 0;
return -EAGAIN;
}
/**
......@@ -1230,20 +1245,23 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
timeout_expire = timeout ?
jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0;
if (INTEL_INFO(dev)->gen >= 6 && ring->id == RCS && can_wait_boost(file_priv)) {
gen6_rps_boost(dev_priv);
if (file_priv)
mod_delayed_work(dev_priv->wq,
&file_priv->mm.idle_work,
msecs_to_jiffies(100));
}
if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring)))
return -ENODEV;
if (INTEL_INFO(dev)->gen >= 6)
gen6_rps_boost(dev_priv, file_priv);
/* Record current time in case interrupted by signal, or wedged */
trace_i915_gem_request_wait_begin(req);
before = ktime_get_raw_ns();
/* Optimistic spin for the next jiffie before touching IRQs */
ret = __i915_spin_request(req);
if (ret == 0)
goto out;
if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) {
ret = -ENODEV;
goto out;
}
for (;;) {
struct timer_list timer;
......@@ -1292,14 +1310,15 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
destroy_timer_on_stack(&timer);
}
}
now = ktime_get_raw_ns();
trace_i915_gem_request_wait_end(req);
if (!irq_test_in_progress)
ring->irq_put(ring);
finish_wait(&ring->irq_queue, &wait);
out:
now = ktime_get_raw_ns();
trace_i915_gem_request_wait_end(req);
if (timeout) {
s64 tres = *timeout - (now - before);
......@@ -2178,6 +2197,10 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
return ret;
list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list);
obj->get_page.sg = obj->pages->sgl;
obj->get_page.last = 0;
return 0;
}
......@@ -2421,7 +2444,6 @@ int __i915_add_request(struct intel_engine_cs *ring,
i915_queue_hangcheck(ring->dev);
cancel_delayed_work_sync(&dev_priv->mm.idle_work);
queue_delayed_work(dev_priv->wq,
&dev_priv->mm.retire_work,
round_jiffies_up_relative(HZ));
......@@ -2516,7 +2538,45 @@ void i915_gem_request_free(struct kref *req_ref)
i915_gem_context_unreference(ctx);
}
kfree(req);
kmem_cache_free(req->i915->requests, req);
}
int i915_gem_request_alloc(struct intel_engine_cs *ring,
struct intel_context *ctx)
{
struct drm_i915_private *dev_priv = to_i915(ring->dev);
struct drm_i915_gem_request *rq;
int ret;
if (ring->outstanding_lazy_request)
return 0;
rq = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL);
if (rq == NULL)
return -ENOMEM;
kref_init(&rq->ref);
rq->i915 = dev_priv;
ret = i915_gem_get_seqno(ring->dev, &rq->seqno);
if (ret) {
kfree(rq);
return ret;
}
rq->ring = ring;
if (i915.enable_execlists)
ret = intel_logical_ring_alloc_request_extras(rq, ctx);
else
ret = intel_ring_alloc_request_extras(rq);
if (ret) {
kfree(rq);
return ret;
}
ring->outstanding_lazy_request = rq;
return 0;
}
struct drm_i915_gem_request *
......@@ -2578,7 +2638,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
struct drm_i915_gem_request,
execlist_link);
list_del(&submit_req->execlist_link);
intel_runtime_pm_put(dev_priv);
if (submit_req->ctx != ring->default_context)
intel_lr_context_unpin(ring, submit_req->ctx);
......@@ -2768,8 +2827,25 @@ i915_gem_idle_work_handler(struct work_struct *work)
{
struct drm_i915_private *dev_priv =
container_of(work, typeof(*dev_priv), mm.idle_work.work);
struct drm_device *dev = dev_priv->dev;
struct intel_engine_cs *ring;
int i;
intel_mark_idle(dev_priv->dev);
for_each_ring(ring, dev_priv, i)
if (!list_empty(&ring->request_list))
return;
intel_mark_idle(dev);
if (mutex_trylock(&dev->struct_mutex)) {
struct intel_engine_cs *ring;
int i;
for_each_ring(ring, dev_priv, i)
i915_gem_batch_pool_fini(&ring->batch_pool);
mutex_unlock(&dev->struct_mutex);
}
}
/**
......@@ -2867,9 +2943,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
ret = __i915_wait_request(req, reset_counter, true,
args->timeout_ns > 0 ? &args->timeout_ns : NULL,
file->driver_priv);
mutex_lock(&dev->struct_mutex);
i915_gem_request_unreference(req);
mutex_unlock(&dev->struct_mutex);
i915_gem_request_unreference__unlocked(req);
return ret;
out:
......@@ -2994,7 +3068,7 @@ int i915_vma_unbind(struct i915_vma *vma)
trace_i915_vma_unbind(vma);
vma->unbind_vma(vma);
vma->vm->unbind_vma(vma);
list_del_init(&vma->mm_list);
if (i915_is_ggtt(vma->vm)) {
......@@ -3515,20 +3589,8 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
if (ret)
goto err_remove_node;
/* allocate before insert / bind */
if (vma->vm->allocate_va_range) {
trace_i915_va_alloc(vma->vm, vma->node.start, vma->node.size,
VM_TO_TRACE_NAME(vma->vm));
ret = vma->vm->allocate_va_range(vma->vm,
vma->node.start,
vma->node.size);
if (ret)
goto err_remove_node;
}
trace_i915_vma_bind(vma, flags);
ret = i915_vma_bind(vma, obj->cache_level,
flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
ret = i915_vma_bind(vma, obj->cache_level, flags);
if (ret)
goto err_finish_gtt;
......@@ -3754,7 +3816,7 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
list_for_each_entry(vma, &obj->vma_list, vma_link)
if (drm_mm_node_allocated(&vma->node)) {
ret = i915_vma_bind(vma, cache_level,
vma->bound & GLOBAL_BIND);
PIN_UPDATE);
if (ret)
return ret;
}
......@@ -3852,24 +3914,6 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
return ret;
}
static bool is_pin_display(struct drm_i915_gem_object *obj)
{
struct i915_vma *vma;
vma = i915_gem_obj_to_ggtt(obj);
if (!vma)
return false;
/* There are 2 sources that pin objects:
* 1. The display engine (scanouts, sprites, cursors);
* 2. Reservations for execbuffer;
*
* We can ignore reservations as we hold the struct_mutex and
* are only called outside of the reservation path.
*/
return vma->pin_count;
}
/*
* Prepare buffer for display plane (scanout, cursors, etc).
* Can be called from an uninterruptible phase (modesetting) and allows
......@@ -3882,7 +3926,6 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
const struct i915_ggtt_view *view)
{
u32 old_read_domains, old_write_domain;
bool was_pin_display;
int ret;
if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
......@@ -3894,8 +3937,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
/* Mark the pin_display early so that we account for the
* display coherency whilst setting up the cache domains.
*/
was_pin_display = obj->pin_display;
obj->pin_display = true;
obj->pin_display++;
/* The display engine is not coherent with the LLC cache on gen6. As
* a result, we make sure that the pinning that is about to occur is
......@@ -3939,8 +3981,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
return 0;
err_unpin_display:
WARN_ON(was_pin_display != is_pin_display(obj));
obj->pin_display = was_pin_display;
obj->pin_display--;
return ret;
}
......@@ -3948,9 +3989,12 @@ void
i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj,
const struct i915_ggtt_view *view)
{
if (WARN_ON(obj->pin_display == 0))
return;
i915_gem_object_ggtt_unpin_view(obj, view);
obj->pin_display = is_pin_display(obj);
obj->pin_display--;
}
int
......@@ -4072,9 +4116,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
if (ret == 0)
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
mutex_lock(&dev->struct_mutex);
i915_gem_request_unreference(target);
mutex_unlock(&dev->struct_mutex);
i915_gem_request_unreference__unlocked(target);
return ret;
}
......@@ -4155,18 +4197,12 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
bound = vma ? vma->bound : 0;
if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
/* In true PPGTT, bind has possibly changed PDEs, which
* means we must do a context switch before the GPU can
* accurately read some of the VMAs.
*/
vma = i915_gem_object_bind_to_vm(obj, vm, ggtt_view, alignment,
flags);
if (IS_ERR(vma))
return PTR_ERR(vma);
}
if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
} else {
ret = i915_vma_bind(vma, obj->cache_level, flags);
if (ret)
return ret;
}
......@@ -4195,9 +4231,6 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
vma->pin_count++;
if (flags & PIN_MAPPABLE)
obj->pin_mappable |= true;
return 0;
}
......@@ -4235,8 +4268,7 @@ i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj,
WARN_ON(vma->pin_count == 0);
WARN_ON(!i915_gem_obj_ggtt_bound_view(obj, view));
if (--vma->pin_count == 0 && view->type == I915_GGTT_VIEW_NORMAL)
obj->pin_mappable = false;
--vma->pin_count;
}
bool
......@@ -4375,7 +4407,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->obj_exec_link);
INIT_LIST_HEAD(&obj->vma_list);
INIT_LIST_HEAD(&obj->batch_pool_list);
INIT_LIST_HEAD(&obj->batch_pool_link);
obj->ops = ops;
......@@ -4577,7 +4609,7 @@ void i915_gem_vma_destroy(struct i915_vma *vma)
list_del(&vma->vma_link);
kfree(vma);
kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
}
static void
......@@ -4864,12 +4896,12 @@ int i915_gem_init(struct drm_device *dev)
}
if (!i915.enable_execlists) {
dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
dev_priv->gt.init_rings = i915_gem_init_rings;
dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
dev_priv->gt.stop_ring = intel_stop_ring_buffer;
} else {
dev_priv->gt.do_execbuf = intel_execlists_submission;
dev_priv->gt.execbuf_submit = intel_execlists_submission;
dev_priv->gt.init_rings = intel_logical_rings_init;
dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup;
dev_priv->gt.stop_ring = intel_logical_ring_stop;
......@@ -4951,11 +4983,21 @@ i915_gem_load(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
dev_priv->slab =
dev_priv->objects =
kmem_cache_create("i915_gem_object",
sizeof(struct drm_i915_gem_object), 0,
SLAB_HWCACHE_ALIGN,
NULL);
dev_priv->vmas =
kmem_cache_create("i915_gem_vma",
sizeof(struct i915_vma), 0,
SLAB_HWCACHE_ALIGN,
NULL);
dev_priv->requests =
kmem_cache_create("i915_gem_request",
sizeof(struct drm_i915_gem_request), 0,
SLAB_HWCACHE_ALIGN,
NULL);
INIT_LIST_HEAD(&dev_priv->vm_list);
i915_init_vm(dev_priv, &dev_priv->gtt.base);
......@@ -4998,8 +5040,6 @@ i915_gem_load(struct drm_device *dev)
i915_gem_shrinker_init(dev_priv);
i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
mutex_init(&dev_priv->fb_tracking.lock);
}
......@@ -5007,8 +5047,6 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
cancel_delayed_work_sync(&file_priv->mm.idle_work);
/* Clean up our request list when the client is going away, so that
* later retire_requests won't dereference our soon-to-be-gone
* file_priv.
......@@ -5024,15 +5062,12 @@ void i915_gem_release(struct drm_device *dev, struct drm_file *file)
request->file_priv = NULL;
}
spin_unlock(&file_priv->mm.lock);
}
static void
i915_gem_file_idle_work_handler(struct work_struct *work)
{
struct drm_i915_file_private *file_priv =
container_of(work, typeof(*file_priv), mm.idle_work.work);
atomic_set(&file_priv->rps_wait_boost, false);
if (!list_empty(&file_priv->rps_boost)) {
mutex_lock(&to_i915(dev)->rps.hw_lock);
list_del(&file_priv->rps_boost);
mutex_unlock(&to_i915(dev)->rps.hw_lock);
}
}
int i915_gem_open(struct drm_device *dev, struct drm_file *file)
......@@ -5049,11 +5084,10 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
file->driver_priv = file_priv;
file_priv->dev_priv = dev->dev_private;
file_priv->file = file;
INIT_LIST_HEAD(&file_priv->rps_boost);
spin_lock_init(&file_priv->mm.lock);
INIT_LIST_HEAD(&file_priv->mm.request_list);
INIT_DELAYED_WORK(&file_priv->mm.idle_work,
i915_gem_file_idle_work_handler);
ret = i915_gem_context_open(dev, file);
if (ret)
......@@ -5123,7 +5157,7 @@ i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o,
i915_ggtt_view_equal(&vma->ggtt_view, view))
return vma->node.start;
WARN(1, "global vma for this object not found.\n");
WARN(1, "global vma for this object not found. (view=%u)\n", view->type);
return -1;
}
......
......@@ -23,6 +23,7 @@
*/
#include "i915_drv.h"
#include "i915_gem_batch_pool.h"
/**
* DOC: batch pool
......@@ -46,8 +47,12 @@
void i915_gem_batch_pool_init(struct drm_device *dev,
struct i915_gem_batch_pool *pool)
{
int n;
pool->dev = dev;
INIT_LIST_HEAD(&pool->cache_list);
for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++)
INIT_LIST_HEAD(&pool->cache_list[n]);
}
/**
......@@ -58,33 +63,35 @@ void i915_gem_batch_pool_init(struct drm_device *dev,
*/
void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool)
{
WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
int n;
while (!list_empty(&pool->cache_list)) {
struct drm_i915_gem_object *obj =
list_first_entry(&pool->cache_list,
struct drm_i915_gem_object,
batch_pool_list);
WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
WARN_ON(obj->active);
for (n = 0; n < ARRAY_SIZE(pool->cache_list); n++) {
while (!list_empty(&pool->cache_list[n])) {
struct drm_i915_gem_object *obj =
list_first_entry(&pool->cache_list[n],
struct drm_i915_gem_object,
batch_pool_link);
list_del_init(&obj->batch_pool_list);
drm_gem_object_unreference(&obj->base);
list_del(&obj->batch_pool_link);
drm_gem_object_unreference(&obj->base);
}
}
}
/**
* i915_gem_batch_pool_get() - select a buffer from the pool
* i915_gem_batch_pool_get() - allocate a buffer from the pool
* @pool: the batch buffer pool
* @size: the minimum desired size of the returned buffer
*
* Finds or allocates a batch buffer in the pool with at least the requested
* size. The caller is responsible for any domain, active/inactive, or
* purgeability management for the returned buffer.
* Returns an inactive buffer from @pool with at least @size bytes,
* with the pages pinned. The caller must i915_gem_object_unpin_pages()
* on the returned object.
*
* Note: Callers must hold the struct_mutex
*
* Return: the selected batch buffer object
* Return: the buffer object or an error pointer
*/
struct drm_i915_gem_object *
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
......@@ -92,46 +99,53 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
{
struct drm_i915_gem_object *obj = NULL;
struct drm_i915_gem_object *tmp, *next;
struct list_head *list;
int n;
WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
list_for_each_entry_safe(tmp, next,
&pool->cache_list, batch_pool_list) {
/* Compute a power-of-two bucket, but throw everything greater than
* 16KiB into the same bucket: i.e. the the buckets hold objects of
* (1 page, 2 pages, 4 pages, 8+ pages).
*/
n = fls(size >> PAGE_SHIFT) - 1;
if (n >= ARRAY_SIZE(pool->cache_list))
n = ARRAY_SIZE(pool->cache_list) - 1;
list = &pool->cache_list[n];
list_for_each_entry_safe(tmp, next, list, batch_pool_link) {
/* The batches are strictly LRU ordered */
if (tmp->active)
continue;
break;
/* While we're looping, do some clean up */
if (tmp->madv == __I915_MADV_PURGED) {
list_del(&tmp->batch_pool_list);
list_del(&tmp->batch_pool_link);
drm_gem_object_unreference(&tmp->base);
continue;
}
/*
* Select a buffer that is at least as big as needed
* but not 'too much' bigger. A better way to do this
* might be to bucket the pool objects based on size.
*/
if (tmp->base.size >= size &&
tmp->base.size <= (2 * size)) {
if (tmp->base.size >= size) {
obj = tmp;
break;
}
}
if (!obj) {
if (obj == NULL) {
int ret;
obj = i915_gem_alloc_object(pool->dev, size);
if (!obj)
if (obj == NULL)
return ERR_PTR(-ENOMEM);
list_add_tail(&obj->batch_pool_list, &pool->cache_list);
}
else
/* Keep list in LRU order */
list_move_tail(&obj->batch_pool_list, &pool->cache_list);
ret = i915_gem_object_get_pages(obj);
if (ret)
return ERR_PTR(ret);
obj->madv = I915_MADV_WILLNEED;
obj->madv = I915_MADV_DONTNEED;
}
list_move_tail(&obj->batch_pool_link, list);
i915_gem_object_pin_pages(obj);
return obj;
}
/*
* Copyright © 2014 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.
*
*/
#ifndef I915_GEM_BATCH_POOL_H
#define I915_GEM_BATCH_POOL_H
#include "i915_drv.h"
struct i915_gem_batch_pool {
struct drm_device *dev;
struct list_head cache_list[4];
};
/* i915_gem_batch_pool.c */
void i915_gem_batch_pool_init(struct drm_device *dev,
struct i915_gem_batch_pool *pool);
void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
struct drm_i915_gem_object*
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
#endif /* I915_GEM_BATCH_POOL_H */
......@@ -157,7 +157,9 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
struct drm_i915_gem_object *obj;
int ret;
obj = i915_gem_alloc_object(dev, size);
obj = i915_gem_object_create_stolen(dev, size);
if (obj == NULL)
obj = i915_gem_alloc_object(dev, size);
if (obj == NULL)
return ERR_PTR(-ENOMEM);
......@@ -573,20 +575,12 @@ static inline bool should_skip_switch(struct intel_engine_cs *ring,
struct intel_context *from,
struct intel_context *to)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
if (to->remap_slice)
return false;
if (to->ppgtt) {
if (from == to && !test_bit(ring->id,
&to->ppgtt->pd_dirty_rings))
return true;
} else if (dev_priv->mm.aliasing_ppgtt) {
if (from == to && !test_bit(ring->id,
&dev_priv->mm.aliasing_ppgtt->pd_dirty_rings))
return true;
}
if (to->ppgtt && from == to &&
!(intel_ring_flag(ring) & to->ppgtt->pd_dirty_rings))
return true;
return false;
}
......@@ -636,7 +630,6 @@ static int do_switch(struct intel_engine_cs *ring,
struct intel_context *from = ring->last_context;
u32 hw_flags = 0;
bool uninitialized = false;
struct i915_vma *vma;
int ret, i;
if (from != NULL && ring == &dev_priv->ring[RCS]) {
......@@ -673,7 +666,7 @@ static int do_switch(struct intel_engine_cs *ring,
goto unpin_out;
/* Doing a PD load always reloads the page dirs */
clear_bit(ring->id, &to->ppgtt->pd_dirty_rings);
to->ppgtt->pd_dirty_rings &= ~intel_ring_flag(ring);
}
if (ring != &dev_priv->ring[RCS]) {
......@@ -694,16 +687,6 @@ static int do_switch(struct intel_engine_cs *ring,
if (ret)
goto unpin_out;
vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
if (!(vma->bound & GLOBAL_BIND)) {
ret = i915_vma_bind(vma,
to->legacy_hw_ctx.rcs_state->cache_level,
GLOBAL_BIND);
/* This shouldn't ever fail. */
if (WARN_ONCE(ret, "GGTT context bind failed!"))
goto unpin_out;
}
if (!to->legacy_hw_ctx.initialized) {
hw_flags |= MI_RESTORE_INHIBIT;
/* NB: If we inhibit the restore, the context is not allowed to
......@@ -711,12 +694,14 @@ static int do_switch(struct intel_engine_cs *ring,
* space. This means we must enforce that a page table load
* occur when this occurs. */
} else if (to->ppgtt &&
test_and_clear_bit(ring->id, &to->ppgtt->pd_dirty_rings))
(intel_ring_flag(ring) & to->ppgtt->pd_dirty_rings)) {
hw_flags |= MI_FORCE_RESTORE;
to->ppgtt->pd_dirty_rings &= ~intel_ring_flag(ring);
}
/* We should never emit switch_mm more than once */
WARN_ON(needs_pd_load_pre(ring, to) &&
needs_pd_load_post(ring, to, hw_flags));
needs_pd_load_post(ring, to, hw_flags));
ret = mi_set_context(ring, to, hw_flags);
if (ret)
......
......@@ -37,7 +37,6 @@
#define __EXEC_OBJECT_HAS_FENCE (1<<30)
#define __EXEC_OBJECT_NEEDS_MAP (1<<29)
#define __EXEC_OBJECT_NEEDS_BIAS (1<<28)
#define __EXEC_OBJECT_PURGEABLE (1<<27)
#define BATCH_OFFSET_BIAS (256*1024)
......@@ -224,12 +223,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
if (entry->flags & __EXEC_OBJECT_HAS_PIN)
vma->pin_count--;
if (entry->flags & __EXEC_OBJECT_PURGEABLE)
obj->madv = I915_MADV_DONTNEED;
entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE |
__EXEC_OBJECT_HAS_PIN |
__EXEC_OBJECT_PURGEABLE);
entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
}
static void eb_destroy(struct eb_vmas *eb)
......@@ -406,10 +400,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
* pipe_control writes because the gpu doesn't properly redirect them
* through the ppgtt for non_secure batchbuffers. */
if (unlikely(IS_GEN6(dev) &&
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
!(target_vma->bound & GLOBAL_BIND))) {
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION)) {
ret = i915_vma_bind(target_vma, target_i915_obj->cache_level,
GLOBAL_BIND);
PIN_GLOBAL);
if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!"))
return ret;
}
......@@ -591,12 +584,13 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
uint64_t flags;
int ret;
flags = 0;
flags = PIN_USER;
if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
flags |= PIN_GLOBAL;
if (!drm_mm_node_allocated(&vma->node)) {
if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
flags |= PIN_GLOBAL | PIN_MAPPABLE;
if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
flags |= PIN_GLOBAL;
if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
flags |= BATCH_OFFSET_BIAS | PIN_OFFSET_BIAS;
}
......@@ -606,7 +600,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
only_mappable_for_reloc(entry->flags))
ret = i915_gem_object_pin(obj, vma->vm,
entry->alignment,
flags & ~(PIN_GLOBAL | PIN_MAPPABLE));
flags & ~PIN_MAPPABLE);
if (ret)
return ret;
......@@ -1142,12 +1136,11 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
u32 batch_len,
bool is_master)
{
struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
struct drm_i915_gem_object *shadow_batch_obj;
struct i915_vma *vma;
int ret;
shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool,
shadow_batch_obj = i915_gem_batch_pool_get(&ring->batch_pool,
PAGE_ALIGN(batch_len));
if (IS_ERR(shadow_batch_obj))
return shadow_batch_obj;
......@@ -1165,11 +1158,13 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
if (ret)
goto err;
i915_gem_object_unpin_pages(shadow_batch_obj);
memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
vma->exec_entry = shadow_exec_entry;
vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE | __EXEC_OBJECT_HAS_PIN;
vma->exec_entry->flags = __EXEC_OBJECT_HAS_PIN;
drm_gem_object_reference(&shadow_batch_obj->base);
list_add_tail(&vma->exec_list, &eb->vmas);
......@@ -1178,6 +1173,7 @@ i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
return shadow_batch_obj;
err:
i915_gem_object_unpin_pages(shadow_batch_obj);
if (ret == -EACCES) /* unhandled chained batch */
return batch_obj;
else
......@@ -1251,12 +1247,8 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
if (ret)
goto error;
if (ctx->ppgtt)
WARN(ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
"%s didn't clear reload\n", ring->name);
else if (dev_priv->mm.aliasing_ppgtt)
WARN(dev_priv->mm.aliasing_ppgtt->pd_dirty_rings &
(1<<ring->id), "%s didn't clear reload\n", ring->name);
WARN(ctx->ppgtt && ctx->ppgtt->pd_dirty_rings & (1<<ring->id),
"%s didn't clear reload\n", ring->name);
instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
instp_mask = I915_EXEC_CONSTANTS_MASK;
......@@ -1566,12 +1558,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* dispatch_execbuffer implementations. We specifically
* don't want that set when the command parser is
* enabled.
*
* FIXME: with aliasing ppgtt, buffers that should only
* be in ggtt still end up in the aliasing ppgtt. remove
* this check when that is fixed.
*/
if (USES_FULL_PPGTT(dev))
if (USES_PPGTT(dev))
dispatch_flags |= I915_DISPATCH_SECURE;
exec_start = 0;
......@@ -1601,9 +1589,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
} else
exec_start += i915_gem_obj_offset(batch_obj, vm);
ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
&eb->vmas, batch_obj, exec_start,
dispatch_flags);
ret = dev_priv->gt.execbuf_submit(dev, file, ring, ctx, args,
&eb->vmas, batch_obj, exec_start,
dispatch_flags);
/*
* FIXME: We crucially rely upon the active tracking for the (ppgtt)
......
此差异已折叠。
......@@ -158,7 +158,6 @@ struct i915_vma {
/** Flags and address space this VMA is bound to */
#define GLOBAL_BIND (1<<0)
#define LOCAL_BIND (1<<1)
#define PTE_READ_ONLY (1<<2)
unsigned int bound : 4;
/**
......@@ -196,36 +195,30 @@ struct i915_vma {
* bits with absolutely no headroom. So use 4 bits. */
unsigned int pin_count:4;
#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
/** Unmap an object from an address space. This usually consists of
* setting the valid PTE entries to a reserved scratch page. */
void (*unbind_vma)(struct i915_vma *vma);
/* Map an object into an address space with the given cache flags. */
void (*bind_vma)(struct i915_vma *vma,
enum i915_cache_level cache_level,
u32 flags);
};
struct i915_page_table_entry {
struct i915_page_table {
struct page *page;
dma_addr_t daddr;
unsigned long *used_ptes;
};
struct i915_page_directory_entry {
struct i915_page_directory {
struct page *page; /* NULL for GEN6-GEN7 */
union {
uint32_t pd_offset;
dma_addr_t daddr;
};
struct i915_page_table_entry *page_table[I915_PDES]; /* PDEs */
unsigned long *used_pdes;
struct i915_page_table *page_table[I915_PDES]; /* PDEs */
};
struct i915_page_directory_pointer_entry {
struct i915_page_directory_pointer {
/* struct page *page; */
struct i915_page_directory_entry *page_directory[GEN8_LEGACY_PDPES];
DECLARE_BITMAP(used_pdpes, GEN8_LEGACY_PDPES);
struct i915_page_directory *page_directory[GEN8_LEGACY_PDPES];
};
struct i915_address_space {
......@@ -267,6 +260,8 @@ struct i915_address_space {
gen6_pte_t (*pte_encode)(dma_addr_t addr,
enum i915_cache_level level,
bool valid, u32 flags); /* Create a valid PTE */
/* flags for pte_encode */
#define PTE_READ_ONLY (1<<0)
int (*allocate_va_range)(struct i915_address_space *vm,
uint64_t start,
uint64_t length);
......@@ -279,6 +274,13 @@ struct i915_address_space {
uint64_t start,
enum i915_cache_level cache_level, u32 flags);
void (*cleanup)(struct i915_address_space *vm);
/** Unmap an object from an address space. This usually consists of
* setting the valid PTE entries to a reserved scratch page. */
void (*unbind_vma)(struct i915_vma *vma);
/* Map an object into an address space with the given cache flags. */
int (*bind_vma)(struct i915_vma *vma,
enum i915_cache_level cache_level,
u32 flags);
};
/* The Graphics Translation Table is the way in which GEN hardware translates a
......@@ -314,14 +316,13 @@ struct i915_hw_ppgtt {
struct kref ref;
struct drm_mm_node node;
unsigned long pd_dirty_rings;
unsigned num_pd_entries;
unsigned num_pd_pages; /* gen8+ */
union {
struct i915_page_directory_pointer_entry pdp;
struct i915_page_directory_entry pd;
struct i915_page_directory_pointer pdp;
struct i915_page_directory pd;
};
struct i915_page_table_entry *scratch_pt;
struct i915_page_table *scratch_pt;
struct i915_page_directory *scratch_pd;
struct drm_i915_file_private *file_priv;
......@@ -349,6 +350,11 @@ struct i915_hw_ppgtt {
temp = min_t(unsigned, temp, length), \
start += temp, length -= temp)
#define gen6_for_all_pdes(pt, ppgtt, iter) \
for (iter = 0; \
pt = ppgtt->pd.page_table[iter], iter < I915_PDES; \
iter++)
static inline uint32_t i915_pte_index(uint64_t address, uint32_t pde_shift)
{
const uint32_t mask = NUM_PTE(pde_shift) - 1;
......@@ -397,6 +403,63 @@ static inline uint32_t gen6_pde_index(uint32_t addr)
return i915_pde_index(addr, GEN6_PDE_SHIFT);
}
/* Equivalent to the gen6 version, For each pde iterates over every pde
* between from start until start + length. On gen8+ it simply iterates
* over every page directory entry in a page directory.
*/
#define gen8_for_each_pde(pt, pd, start, length, temp, iter) \
for (iter = gen8_pde_index(start); \
pt = (pd)->page_table[iter], length > 0 && iter < I915_PDES; \
iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDE_SHIFT) - start, \
temp = min(temp, length), \
start += temp, length -= temp)
#define gen8_for_each_pdpe(pd, pdp, start, length, temp, iter) \
for (iter = gen8_pdpe_index(start); \
pd = (pdp)->page_directory[iter], length > 0 && iter < GEN8_LEGACY_PDPES; \
iter++, \
temp = ALIGN(start+1, 1 << GEN8_PDPE_SHIFT) - start, \
temp = min(temp, length), \
start += temp, length -= temp)
/* Clamp length to the next page_directory boundary */
static inline uint64_t gen8_clamp_pd(uint64_t start, uint64_t length)
{
uint64_t next_pd = ALIGN(start + 1, 1 << GEN8_PDPE_SHIFT);
if (next_pd > (start + length))
return length;
return next_pd - start;
}
static inline uint32_t gen8_pte_index(uint64_t address)
{
return i915_pte_index(address, GEN8_PDE_SHIFT);
}
static inline uint32_t gen8_pde_index(uint64_t address)
{
return i915_pde_index(address, GEN8_PDE_SHIFT);
}
static inline uint32_t gen8_pdpe_index(uint64_t address)
{
return (address >> GEN8_PDPE_SHIFT) & GEN8_PDPE_MASK;
}
static inline uint32_t gen8_pml4e_index(uint64_t address)
{
WARN_ON(1); /* For 64B */
return 0;
}
static inline size_t gen8_pte_count(uint64_t address, uint64_t length)
{
return i915_pte_count(address, length, GEN8_PDE_SHIFT);
}
int i915_gem_gtt_init(struct drm_device *dev);
void i915_gem_init_global_gtt(struct drm_device *dev);
void i915_global_gtt_cleanup(struct drm_device *dev);
......
......@@ -184,9 +184,12 @@ static int num_vma_bound(struct drm_i915_gem_object *obj)
struct i915_vma *vma;
int count = 0;
list_for_each_entry(vma, &obj->vma_list, vma_link)
list_for_each_entry(vma, &obj->vma_list, vma_link) {
if (drm_mm_node_allocated(&vma->node))
count++;
if (vma->pin_count)
count++;
}
return count;
}
......@@ -210,8 +213,7 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
count += obj->base.size >> PAGE_SHIFT;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
if (!i915_gem_obj_is_pinned(obj) &&
obj->pages_pin_count == num_vma_bound(obj))
if (obj->pages_pin_count == num_vma_bound(obj))
count += obj->base.size >> PAGE_SHIFT;
}
......
......@@ -209,7 +209,7 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp)
dev_priv->fbc.threshold = ret;
if (HAS_PCH_SPLIT(dev))
if (INTEL_INFO(dev_priv)->gen >= 5)
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start);
else if (IS_GM45(dev)) {
I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start);
......
......@@ -336,7 +336,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
mutex_lock(&dev->struct_mutex);
if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
if (obj->pin_display || obj->framebuffer_references) {
ret = -EBUSY;
goto err;
}
......
......@@ -251,10 +251,11 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
return;
err_printf(m, "%s command stream:\n", ring_str(ring_idx));
err_printf(m, " HEAD: 0x%08x\n", ring->head);
err_printf(m, " TAIL: 0x%08x\n", ring->tail);
err_printf(m, " CTL: 0x%08x\n", ring->ctl);
err_printf(m, " HWS: 0x%08x\n", ring->hws);
err_printf(m, " START: 0x%08x\n", ring->start);
err_printf(m, " HEAD: 0x%08x\n", ring->head);
err_printf(m, " TAIL: 0x%08x\n", ring->tail);
err_printf(m, " CTL: 0x%08x\n", ring->ctl);
err_printf(m, " HWS: 0x%08x\n", ring->hws);
err_printf(m, " ACTHD: 0x%08x %08x\n", (u32)(ring->acthd>>32), (u32)ring->acthd);
err_printf(m, " IPEIR: 0x%08x\n", ring->ipeir);
err_printf(m, " IPEHR: 0x%08x\n", ring->ipehr);
......@@ -883,6 +884,7 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->instpm = I915_READ(RING_INSTPM(ring->mmio_base));
ering->seqno = ring->get_seqno(ring, false);
ering->acthd = intel_ring_get_active_head(ring);
ering->start = I915_READ_START(ring);
ering->head = I915_READ_HEAD(ring);
ering->tail = I915_READ_TAIL(ring);
ering->ctl = I915_READ_CTL(ring);
......
此差异已折叠。
此差异已折叠。
......@@ -220,7 +220,7 @@ DEFINE_EVENT(i915_page_table_entry, i915_page_table_entry_alloc,
DECLARE_EVENT_CLASS(i915_page_table_entry_update,
TP_PROTO(struct i915_address_space *vm, u32 pde,
struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
struct i915_page_table *pt, u32 first, u32 count, u32 bits),
TP_ARGS(vm, pde, pt, first, count, bits),
TP_STRUCT__entry(
......@@ -250,7 +250,7 @@ DECLARE_EVENT_CLASS(i915_page_table_entry_update,
DEFINE_EVENT(i915_page_table_entry_update, i915_page_table_entry_map,
TP_PROTO(struct i915_address_space *vm, u32 pde,
struct i915_page_table_entry *pt, u32 first, u32 count, u32 bits),
struct i915_page_table *pt, u32 first, u32 count, u32 bits),
TP_ARGS(vm, pde, pt, first, count, bits)
);
......@@ -504,7 +504,6 @@ DECLARE_EVENT_CLASS(i915_gem_request,
TP_STRUCT__entry(
__field(u32, dev)
__field(u32, ring)
__field(u32, uniq)
__field(u32, seqno)
),
......@@ -513,13 +512,11 @@ DECLARE_EVENT_CLASS(i915_gem_request,
i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
__entry->uniq = req ? req->uniq : 0;
__entry->seqno = i915_gem_request_get_seqno(req);
),
TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u",
__entry->dev, __entry->ring, __entry->uniq,
__entry->seqno)
TP_printk("dev=%u, ring=%u, seqno=%u",
__entry->dev, __entry->ring, __entry->seqno)
);
DEFINE_EVENT(i915_gem_request, i915_gem_request_add,
......@@ -564,7 +561,6 @@ TRACE_EVENT(i915_gem_request_wait_begin,
TP_STRUCT__entry(
__field(u32, dev)
__field(u32, ring)
__field(u32, uniq)
__field(u32, seqno)
__field(bool, blocking)
),
......@@ -580,14 +576,13 @@ TRACE_EVENT(i915_gem_request_wait_begin,
i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
__entry->uniq = req ? req->uniq : 0;
__entry->seqno = i915_gem_request_get_seqno(req);
__entry->blocking =
mutex_is_locked(&ring->dev->struct_mutex);
),
TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u, blocking=%s",
__entry->dev, __entry->ring, __entry->uniq,
TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s",
__entry->dev, __entry->ring,
__entry->seqno, __entry->blocking ? "yes (NB)" : "no")
);
......@@ -596,33 +591,6 @@ DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
TP_ARGS(req)
);
DECLARE_EVENT_CLASS(i915_ring,
TP_PROTO(struct intel_engine_cs *ring),
TP_ARGS(ring),
TP_STRUCT__entry(
__field(u32, dev)
__field(u32, ring)
),
TP_fast_assign(
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
),
TP_printk("dev=%u, ring=%u", __entry->dev, __entry->ring)
);
DEFINE_EVENT(i915_ring, i915_ring_wait_begin,
TP_PROTO(struct intel_engine_cs *ring),
TP_ARGS(ring)
);
DEFINE_EVENT(i915_ring, i915_ring_wait_end,
TP_PROTO(struct intel_engine_cs *ring),
TP_ARGS(ring)
);
TRACE_EVENT(i915_flip_request,
TP_PROTO(int plane, struct drm_i915_gem_object *obj),
......
此差异已折叠。
......@@ -162,6 +162,30 @@ static int intel_plane_atomic_check(struct drm_plane *plane,
(1 << drm_plane_index(plane));
}
if (state->fb && intel_rotation_90_or_270(state->rotation)) {
if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) {
DRM_DEBUG_KMS("Y/Yf tiling required for 90/270!\n");
return -EINVAL;
}
/*
* 90/270 is not allowed with RGB64 16:16:16:16,
* RGB 16-bit 5:6:5, and Indexed 8-bit.
* TBD: Add RGB64 case once its added in supported format list.
*/
switch (state->fb->pixel_format) {
case DRM_FORMAT_C8:
case DRM_FORMAT_RGB565:
DRM_DEBUG_KMS("Unsupported pixel format %s for 90/270!\n",
drm_get_format_name(state->fb->pixel_format));
return -EINVAL;
default:
break;
}
}
return intel_plane->check_plane(plane, intel_state);
}
......
此差异已折叠。
此差异已折叠。
......@@ -277,9 +277,9 @@ struct bdb_general_definitions {
* And the device num is related with the size of general definition
* block. It is obtained by using the following formula:
* number = (block_size - sizeof(bdb_general_definitions))/
* sizeof(child_device_config);
* defs->child_dev_size;
*/
union child_device_config devices[0];
uint8_t devices[0];
} __packed;
/* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部