Commit a7e2641a authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-intel-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-intel into drm-next

Final block of feature work for 4.11:

- gen8 pd cleanup from Matthew Auld
- more cleanups for view/vma (Chris)
- dmc support on glk (Anusha Srivatsa)
- use core crc api (Tomue)
- track wedged requests using fence.error (Chris)
- lots of psr fixes (Nagaraju, Vathsala)
- dp mst support, acked for merging through drm-intel by Takashi
  (Libin)
- huc loading support, including uapi for libva to use it (Anusha
  Srivatsa)

* tag 'drm-intel-next-2017-01-23' of git://anongit.freedesktop.org/git/drm-intel: (111 commits)
  drm/i915: Update DRIVER_DATE to 20170123
  drm/i915: reinstate call to trace_i915_vma_bind
  drm/i915: Assert that created vma has a whole number of pages
  drm/i915: Assert the drm_mm_node is allocated when on the VM lists
  drm/i915: Treat an error from i915_vma_instance() as unlikely
  drm/i915: Reject vma creation larger than address space
  drm/i915: Use common LRU inactive vma bumping for unpin_from_display
  drm/i915: Do an unlocked wait before set-cache-level ioctl
  drm/i915/huc: Assert that HuC vma is placed in GuC accessible range
  drm/i915/huc: Avoid attempting to authenticate non-existent fw
  drm/i915: Set adjustment to zero on Up/Down interrupts if freq is already max/min
  drm/i915: Remove the double handling of 'flags from intel_mode_from_pipe_config()
  drm/i915: Remove crtc->config usage from intel_modeset_readout_hw_state()
  drm/i915: Release temporary load-detect state upon switching
  drm/i915: Remove i915_gem_object_to_ggtt()
  drm/i915: Remove i915_vma_create from VMA API
  drm/i915: Add a check that the VMA instance we lookup matches the request
  drm/i915: Rename some warts in the VMA API
  drm/i915: Track pinned vma in intel_plane_state
  drm/i915/get_params: Add HuC status to getparams
  ...
parents c4d79c22 add6329c
...@@ -19,6 +19,23 @@ PCM ...@@ -19,6 +19,23 @@ PCM
=== ===
To be added To be added
Pin Initialization
==================
Each pin may have several device entries (virtual pins). On Intel platform,
the device entries number is dynamically changed. If DP MST hub is connected,
it is in DP MST mode, and the device entries number is 3. Otherwise, the
device entries number is 1.
To simplify the implementation, all the device entries will be initialized
when bootup no matter whether it is in DP MST mode or not.
Connection list
===============
DP MST reuses connection list code. The code can be reused because
device entries on the same pin have the same connection list.
This means DP MST gets the device entry connection list without the
device entry setting.
Jack Jack
==== ====
......
...@@ -56,7 +56,9 @@ i915-y += i915_cmd_parser.o \ ...@@ -56,7 +56,9 @@ i915-y += i915_cmd_parser.o \
# general-purpose microcontroller (GuC) support # general-purpose microcontroller (GuC) support
i915-y += intel_uc.o \ i915-y += intel_uc.o \
intel_guc_log.o \
intel_guc_loader.o \ intel_guc_loader.o \
intel_huc.o \
i915_guc_submission.o i915_guc_submission.o
# autogenerated null render state # autogenerated null render state
......
...@@ -41,47 +41,34 @@ static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) ...@@ -41,47 +41,34 @@ static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm)
{ {
struct intel_gvt *gvt = vgpu->gvt; struct intel_gvt *gvt = vgpu->gvt;
struct drm_i915_private *dev_priv = gvt->dev_priv; struct drm_i915_private *dev_priv = gvt->dev_priv;
u32 alloc_flag, search_flag; unsigned int flags;
u64 start, end, size; u64 start, end, size;
struct drm_mm_node *node; struct drm_mm_node *node;
int retried = 0;
int ret; int ret;
if (high_gm) { if (high_gm) {
search_flag = DRM_MM_SEARCH_BELOW;
alloc_flag = DRM_MM_CREATE_TOP;
node = &vgpu->gm.high_gm_node; node = &vgpu->gm.high_gm_node;
size = vgpu_hidden_sz(vgpu); size = vgpu_hidden_sz(vgpu);
start = gvt_hidden_gmadr_base(gvt); start = gvt_hidden_gmadr_base(gvt);
end = gvt_hidden_gmadr_end(gvt); end = gvt_hidden_gmadr_end(gvt);
flags = PIN_HIGH;
} else { } else {
search_flag = DRM_MM_SEARCH_DEFAULT;
alloc_flag = DRM_MM_CREATE_DEFAULT;
node = &vgpu->gm.low_gm_node; node = &vgpu->gm.low_gm_node;
size = vgpu_aperture_sz(vgpu); size = vgpu_aperture_sz(vgpu);
start = gvt_aperture_gmadr_base(gvt); start = gvt_aperture_gmadr_base(gvt);
end = gvt_aperture_gmadr_end(gvt); end = gvt_aperture_gmadr_end(gvt);
flags = PIN_MAPPABLE;
} }
mutex_lock(&dev_priv->drm.struct_mutex); mutex_lock(&dev_priv->drm.struct_mutex);
search_again: ret = i915_gem_gtt_insert(&dev_priv->ggtt.base, node,
ret = drm_mm_insert_node_in_range_generic(&dev_priv->ggtt.base.mm, size, 4096, I915_COLOR_UNEVICTABLE,
node, size, 4096, start, end, flags);
I915_COLOR_UNEVICTABLE,
start, end, search_flag,
alloc_flag);
if (ret) {
ret = i915_gem_evict_something(&dev_priv->ggtt.base,
size, 4096,
I915_COLOR_UNEVICTABLE,
start, end, 0);
if (ret == 0 && ++retried < 3)
goto search_again;
gvt_err("fail to alloc %s gm space from host, retried %d\n",
high_gm ? "high" : "low", retried);
}
mutex_unlock(&dev_priv->drm.struct_mutex); mutex_unlock(&dev_priv->drm.struct_mutex);
if (ret)
gvt_err("fail to alloc %s gm space from host\n",
high_gm ? "high" : "low");
return ret; return ret;
} }
......
...@@ -159,8 +159,35 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) ...@@ -159,8 +159,35 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_printf(m, " (%sgtt offset: %08llx, size: %08llx", seq_printf(m, " (%sgtt offset: %08llx, size: %08llx",
i915_vma_is_ggtt(vma) ? "g" : "pp", i915_vma_is_ggtt(vma) ? "g" : "pp",
vma->node.start, vma->node.size); vma->node.start, vma->node.size);
if (i915_vma_is_ggtt(vma)) if (i915_vma_is_ggtt(vma)) {
seq_printf(m, ", type: %u", vma->ggtt_view.type); switch (vma->ggtt_view.type) {
case I915_GGTT_VIEW_NORMAL:
seq_puts(m, ", normal");
break;
case I915_GGTT_VIEW_PARTIAL:
seq_printf(m, ", partial [%08llx+%x]",
vma->ggtt_view.partial.offset << PAGE_SHIFT,
vma->ggtt_view.partial.size << PAGE_SHIFT);
break;
case I915_GGTT_VIEW_ROTATED:
seq_printf(m, ", rotated [(%ux%u, stride=%u, offset=%u), (%ux%u, stride=%u, offset=%u)]",
vma->ggtt_view.rotated.plane[0].width,
vma->ggtt_view.rotated.plane[0].height,
vma->ggtt_view.rotated.plane[0].stride,
vma->ggtt_view.rotated.plane[0].offset,
vma->ggtt_view.rotated.plane[1].width,
vma->ggtt_view.rotated.plane[1].height,
vma->ggtt_view.rotated.plane[1].stride,
vma->ggtt_view.rotated.plane[1].offset);
break;
default:
MISSING_CASE(vma->ggtt_view.type);
break;
}
}
if (vma->fence) if (vma->fence)
seq_printf(m, " , fence: %d%s", seq_printf(m, " , fence: %d%s",
vma->fence->id, vma->fence->id,
...@@ -2325,10 +2352,40 @@ static int i915_llc(struct seq_file *m, void *data) ...@@ -2325,10 +2352,40 @@ static int i915_llc(struct seq_file *m, void *data)
return 0; return 0;
} }
static int i915_huc_load_status_info(struct seq_file *m, void *data)
{
struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct intel_uc_fw *huc_fw = &dev_priv->huc.fw;
if (!HAS_HUC_UCODE(dev_priv))
return 0;
seq_puts(m, "HuC firmware status:\n");
seq_printf(m, "\tpath: %s\n", huc_fw->path);
seq_printf(m, "\tfetch: %s\n",
intel_uc_fw_status_repr(huc_fw->fetch_status));
seq_printf(m, "\tload: %s\n",
intel_uc_fw_status_repr(huc_fw->load_status));
seq_printf(m, "\tversion wanted: %d.%d\n",
huc_fw->major_ver_wanted, huc_fw->minor_ver_wanted);
seq_printf(m, "\tversion found: %d.%d\n",
huc_fw->major_ver_found, huc_fw->minor_ver_found);
seq_printf(m, "\theader: offset is %d; size = %d\n",
huc_fw->header_offset, huc_fw->header_size);
seq_printf(m, "\tuCode: offset is %d; size = %d\n",
huc_fw->ucode_offset, huc_fw->ucode_size);
seq_printf(m, "\tRSA: offset is %d; size = %d\n",
huc_fw->rsa_offset, huc_fw->rsa_size);
seq_printf(m, "\nHuC status 0x%08x:\n", I915_READ(HUC_STATUS2));
return 0;
}
static int i915_guc_load_status_info(struct seq_file *m, void *data) static int i915_guc_load_status_info(struct seq_file *m, void *data)
{ {
struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_i915_private *dev_priv = node_to_i915(m->private);
struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; struct intel_uc_fw *guc_fw = &dev_priv->guc.fw;
u32 tmp, i; u32 tmp, i;
if (!HAS_GUC_UCODE(dev_priv)) if (!HAS_GUC_UCODE(dev_priv))
...@@ -2336,15 +2393,15 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data) ...@@ -2336,15 +2393,15 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
seq_printf(m, "GuC firmware status:\n"); seq_printf(m, "GuC firmware status:\n");
seq_printf(m, "\tpath: %s\n", seq_printf(m, "\tpath: %s\n",
guc_fw->guc_fw_path); guc_fw->path);
seq_printf(m, "\tfetch: %s\n", seq_printf(m, "\tfetch: %s\n",
intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status)); intel_uc_fw_status_repr(guc_fw->fetch_status));
seq_printf(m, "\tload: %s\n", seq_printf(m, "\tload: %s\n",
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); intel_uc_fw_status_repr(guc_fw->load_status));
seq_printf(m, "\tversion wanted: %d.%d\n", seq_printf(m, "\tversion wanted: %d.%d\n",
guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted); guc_fw->major_ver_wanted, guc_fw->minor_ver_wanted);
seq_printf(m, "\tversion found: %d.%d\n", seq_printf(m, "\tversion found: %d.%d\n",
guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found); guc_fw->major_ver_found, guc_fw->minor_ver_found);
seq_printf(m, "\theader: offset is %d; size = %d\n", seq_printf(m, "\theader: offset is %d; size = %d\n",
guc_fw->header_offset, guc_fw->header_size); guc_fw->header_offset, guc_fw->header_size);
seq_printf(m, "\tuCode: offset is %d; size = %d\n", seq_printf(m, "\tuCode: offset is %d; size = %d\n",
...@@ -2532,6 +2589,29 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops, ...@@ -2532,6 +2589,29 @@ DEFINE_SIMPLE_ATTRIBUTE(i915_guc_log_control_fops,
i915_guc_log_control_get, i915_guc_log_control_set, i915_guc_log_control_get, i915_guc_log_control_set,
"%lld\n"); "%lld\n");
static const char *psr2_live_status(u32 val)
{
static const char * const live_status[] = {
"IDLE",
"CAPTURE",
"CAPTURE_FS",
"SLEEP",
"BUFON_FW",
"ML_UP",
"SU_STANDBY",
"FAST_SLEEP",
"DEEP_SLEEP",
"BUF_ON",
"TG_ON"
};
val = (val & EDP_PSR2_STATUS_STATE_MASK) >> EDP_PSR2_STATUS_STATE_SHIFT;
if (val < ARRAY_SIZE(live_status))
return live_status[val];
return "unknown";
}
static int i915_edp_psr_status(struct seq_file *m, void *data) static int i915_edp_psr_status(struct seq_file *m, void *data)
{ {
struct drm_i915_private *dev_priv = node_to_i915(m->private); struct drm_i915_private *dev_priv = node_to_i915(m->private);
...@@ -2606,6 +2686,12 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) ...@@ -2606,6 +2686,12 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
seq_printf(m, "Performance_Counter: %u\n", psrperf); seq_printf(m, "Performance_Counter: %u\n", psrperf);
} }
if (dev_priv->psr.psr2_support) {
u32 psr2 = I915_READ(EDP_PSR2_STATUS_CTL);
seq_printf(m, "EDP_PSR2_STATUS_CTL: %x [%s]\n",
psr2, psr2_live_status(psr2));
}
mutex_unlock(&dev_priv->psr.lock); mutex_unlock(&dev_priv->psr.lock);
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
...@@ -4553,6 +4639,7 @@ static const struct drm_info_list i915_debugfs_list[] = { ...@@ -4553,6 +4639,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_guc_info", i915_guc_info, 0}, {"i915_guc_info", i915_guc_info, 0},
{"i915_guc_load_status", i915_guc_load_status_info, 0}, {"i915_guc_load_status", i915_guc_load_status_info, 0},
{"i915_guc_log_dump", i915_guc_log_dump, 0}, {"i915_guc_log_dump", i915_guc_log_dump, 0},
{"i915_huc_load_status", i915_huc_load_status_info, 0},
{"i915_frequency_info", i915_frequency_info, 0}, {"i915_frequency_info", i915_frequency_info, 0},
{"i915_hangcheck_info", i915_hangcheck_info, 0}, {"i915_hangcheck_info", i915_hangcheck_info, 0},
{"i915_drpc_info", i915_drpc_info, 0}, {"i915_drpc_info", i915_drpc_info, 0},
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "i915_trace.h" #include "i915_trace.h"
#include "i915_vgpu.h" #include "i915_vgpu.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "intel_uc.h"
static struct drm_driver driver; static struct drm_driver driver;
...@@ -315,6 +316,12 @@ static int i915_getparam(struct drm_device *dev, void *data, ...@@ -315,6 +316,12 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_MIN_EU_IN_POOL: case I915_PARAM_MIN_EU_IN_POOL:
value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool; value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool;
break; break;
case I915_PARAM_HUC_STATUS:
/* The register is already force-woken. We dont need
* any rpm here
*/
value = I915_READ(HUC_STATUS2) & HUC_FW_VERIFIED;
break;
case I915_PARAM_MMAP_GTT_VERSION: case I915_PARAM_MMAP_GTT_VERSION:
/* Though we've started our numbering from 1, and so class all /* Though we've started our numbering from 1, and so class all
* earlier versions as 0, in effect their value is undefined as * earlier versions as 0, in effect their value is undefined as
...@@ -599,6 +606,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -599,6 +606,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (ret) if (ret)
goto cleanup_irq; goto cleanup_irq;
intel_huc_init(dev_priv);
intel_guc_init(dev_priv); intel_guc_init(dev_priv);
ret = i915_gem_init(dev_priv); ret = i915_gem_init(dev_priv);
...@@ -627,6 +635,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -627,6 +635,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
i915_gem_fini(dev_priv); i915_gem_fini(dev_priv);
cleanup_irq: cleanup_irq:
intel_guc_fini(dev_priv); intel_guc_fini(dev_priv);
intel_huc_fini(dev_priv);
drm_irq_uninstall(dev); drm_irq_uninstall(dev);
intel_teardown_gmbus(dev_priv); intel_teardown_gmbus(dev_priv);
cleanup_csr: cleanup_csr:
...@@ -1114,7 +1123,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) ...@@ -1114,7 +1123,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
/* Reveal our presence to userspace */ /* Reveal our presence to userspace */
if (drm_dev_register(dev, 0) == 0) { if (drm_dev_register(dev, 0) == 0) {
i915_debugfs_register(dev_priv); i915_debugfs_register(dev_priv);
i915_guc_register(dev_priv); i915_guc_log_register(dev_priv);
i915_setup_sysfs(dev_priv); i915_setup_sysfs(dev_priv);
/* Depends on sysfs having been initialized */ /* Depends on sysfs having been initialized */
...@@ -1158,7 +1167,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) ...@@ -1158,7 +1167,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
i915_perf_unregister(dev_priv); i915_perf_unregister(dev_priv);
i915_teardown_sysfs(dev_priv); i915_teardown_sysfs(dev_priv);
i915_guc_unregister(dev_priv); i915_guc_log_unregister(dev_priv);
i915_debugfs_unregister(dev_priv); i915_debugfs_unregister(dev_priv);
drm_dev_unregister(&dev_priv->drm); drm_dev_unregister(&dev_priv->drm);
...@@ -1314,6 +1323,7 @@ void i915_driver_unload(struct drm_device *dev) ...@@ -1314,6 +1323,7 @@ void i915_driver_unload(struct drm_device *dev)
drain_workqueue(dev_priv->wq); drain_workqueue(dev_priv->wq);
intel_guc_fini(dev_priv); intel_guc_fini(dev_priv);
intel_huc_fini(dev_priv);
i915_gem_fini(dev_priv); i915_gem_fini(dev_priv);
intel_fbc_cleanup_cfb(dev_priv); intel_fbc_cleanup_cfb(dev_priv);
...@@ -1471,7 +1481,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) ...@@ -1471,7 +1481,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
intel_display_set_init_power(dev_priv, false); intel_display_set_init_power(dev_priv, false);
fw_csr = !IS_BROXTON(dev_priv) && fw_csr = !IS_GEN9_LP(dev_priv) &&
suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload; suspend_to_idle(dev_priv) && dev_priv->csr.dmc_payload;
/* /*
* In case of firmware assisted context save/restore don't manually * In case of firmware assisted context save/restore don't manually
...@@ -1484,7 +1494,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) ...@@ -1484,7 +1494,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
intel_power_domains_suspend(dev_priv); intel_power_domains_suspend(dev_priv);
ret = 0; ret = 0;
if (IS_BROXTON(dev_priv)) if (IS_GEN9_LP(dev_priv))
bxt_enable_dc9(dev_priv); bxt_enable_dc9(dev_priv);
else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
hsw_enable_pc8(dev_priv); hsw_enable_pc8(dev_priv);
...@@ -1692,7 +1702,7 @@ static int i915_drm_resume_early(struct drm_device *dev) ...@@ -1692,7 +1702,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
intel_uncore_early_sanitize(dev_priv, true); intel_uncore_early_sanitize(dev_priv, true);
if (IS_BROXTON(dev_priv)) { if (IS_GEN9_LP(dev_priv)) {
if (!dev_priv->suspended_to_idle) if (!dev_priv->suspended_to_idle)
gen9_sanitize_dc_state(dev_priv); gen9_sanitize_dc_state(dev_priv);
bxt_disable_dc9(dev_priv); bxt_disable_dc9(dev_priv);
...@@ -1702,7 +1712,7 @@ static int i915_drm_resume_early(struct drm_device *dev) ...@@ -1702,7 +1712,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
intel_uncore_sanitize(dev_priv); intel_uncore_sanitize(dev_priv);
if (IS_BROXTON(dev_priv) || if (IS_GEN9_LP(dev_priv) ||
!(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload)) !(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload))
intel_power_domains_init_hw(dev_priv, true); intel_power_domains_init_hw(dev_priv, true);
...@@ -1728,25 +1738,9 @@ static int i915_resume_switcheroo(struct drm_device *dev) ...@@ -1728,25 +1738,9 @@ static int i915_resume_switcheroo(struct drm_device *dev)
return i915_drm_resume(dev); return i915_drm_resume(dev);
} }
static void disable_engines_irq(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
/* Ensure irq handler finishes, and not run again. */
disable_irq(dev_priv->drm.irq);
for_each_engine(engine, dev_priv, id)
tasklet_kill(&engine->irq_tasklet);
}
static void enable_engines_irq(struct drm_i915_private *dev_priv)
{
enable_irq(dev_priv->drm.irq);
}
/** /**
* i915_reset - reset chip after a hang * i915_reset - reset chip after a hang
* @dev: drm device to reset * @dev_priv: device private to reset
* *
* Reset the chip. Useful if a hang is detected. Marks the device as wedged * Reset the chip. Useful if a hang is detected. Marks the device as wedged
* on failure. * on failure.
...@@ -1776,12 +1770,15 @@ void i915_reset(struct drm_i915_private *dev_priv) ...@@ -1776,12 +1770,15 @@ void i915_reset(struct drm_i915_private *dev_priv)
error->reset_count++; error->reset_count++;
pr_notice("drm/i915: Resetting chip after gpu hang\n"); pr_notice("drm/i915: Resetting chip after gpu hang\n");
i915_gem_reset_prepare(dev_priv); disable_irq(dev_priv->drm.irq);
ret = i915_gem_reset_prepare(dev_priv);
if (ret) {
DRM_ERROR("GPU recovery failed\n");
intel_gpu_reset(dev_priv, ALL_ENGINES);
goto error;
}
disable_engines_irq(dev_priv);
ret = intel_gpu_reset(dev_priv, ALL_ENGINES); ret = intel_gpu_reset(dev_priv, ALL_ENGINES);
enable_engines_irq(dev_priv);
if (ret) { if (ret) {
if (ret != -ENODEV) if (ret != -ENODEV)
DRM_ERROR("Failed to reset chip: %i\n", ret); DRM_ERROR("Failed to reset chip: %i\n", ret);
...@@ -1816,6 +1813,7 @@ void i915_reset(struct drm_i915_private *dev_priv) ...@@ -1816,6 +1813,7 @@ void i915_reset(struct drm_i915_private *dev_priv)
i915_queue_hangcheck(dev_priv); i915_queue_hangcheck(dev_priv);
wakeup: wakeup:
enable_irq(dev_priv->drm.irq);
wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS); wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS);
return; return;
...@@ -2326,7 +2324,7 @@ static int intel_runtime_suspend(struct device *kdev) ...@@ -2326,7 +2324,7 @@ static int intel_runtime_suspend(struct device *kdev)
intel_runtime_pm_disable_interrupts(dev_priv); intel_runtime_pm_disable_interrupts(dev_priv);
ret = 0; ret = 0;
if (IS_BROXTON(dev_priv)) { if (IS_GEN9_LP(dev_priv)) {
bxt_display_core_uninit(dev_priv); bxt_display_core_uninit(dev_priv);
bxt_enable_dc9(dev_priv); bxt_enable_dc9(dev_priv);
} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { } else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
...@@ -2411,7 +2409,7 @@ static int intel_runtime_resume(struct device *kdev) ...@@ -2411,7 +2409,7 @@ static int intel_runtime_resume(struct device *kdev)
if (IS_GEN6(dev_priv)) if (IS_GEN6(dev_priv))
intel_init_pch_refclk(dev_priv); intel_init_pch_refclk(dev_priv);
if (IS_BROXTON(dev_priv)) { if (IS_GEN9_LP(dev_priv)) {
bxt_disable_dc9(dev_priv); bxt_disable_dc9(dev_priv);
bxt_display_core_init(dev_priv, true); bxt_display_core_init(dev_priv, true);
if (dev_priv->csr.dmc_payload && if (dev_priv->csr.dmc_payload &&
...@@ -2549,8 +2547,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = { ...@@ -2549,8 +2547,8 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_SET_TILING, i915_gem_set_tiling_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_GET_TILING, i915_gem_get_tiling_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0), DRM_IOCTL_DEF_DRV(I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(I915_GEM_MADVISE, i915_gem_madvise_ioctl, DRM_RENDER_ALLOW),
......
...@@ -78,8 +78,8 @@ ...@@ -78,8 +78,8 @@
#define DRIVER_NAME "i915" #define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics" #define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20170109" #define DRIVER_DATE "20170123"
#define DRIVER_TIMESTAMP 1483953121 #define DRIVER_TIMESTAMP 1485156432
#undef WARN_ON #undef WARN_ON
/* Many gcc seem to no see through this and fall over :( */ /* Many gcc seem to no see through this and fall over :( */
...@@ -1069,6 +1069,8 @@ struct intel_fbc { ...@@ -1069,6 +1069,8 @@ struct intel_fbc {
struct work_struct underrun_work; struct work_struct underrun_work;
struct intel_fbc_state_cache { struct intel_fbc_state_cache {
struct i915_vma *vma;
struct { struct {
unsigned int mode_flags; unsigned int mode_flags;
uint32_t hsw_bdw_pixel_rate; uint32_t hsw_bdw_pixel_rate;
...@@ -1082,15 +1084,14 @@ struct intel_fbc { ...@@ -1082,15 +1084,14 @@ struct intel_fbc {
} plane; } plane;
struct { struct {
u64 ilk_ggtt_offset;
const struct drm_format_info *format; const struct drm_format_info *format;
unsigned int stride; unsigned int stride;
int fence_reg;
unsigned int tiling_mode;
} fb; } fb;
} state_cache; } state_cache;
struct intel_fbc_reg_params { struct intel_fbc_reg_params {
struct i915_vma *vma;
struct { struct {
enum pipe pipe; enum pipe pipe;
enum plane plane; enum plane plane;
...@@ -1098,10 +1099,8 @@ struct intel_fbc { ...@@ -1098,10 +1099,8 @@ struct intel_fbc {
} crtc; } crtc;
struct { struct {
u64 ggtt_offset;
const struct drm_format_info *format; const struct drm_format_info *format;
unsigned int stride; unsigned int stride;
int fence_reg;
} fb; } fb;
int cfb_size; int cfb_size;
...@@ -1154,6 +1153,9 @@ struct i915_psr { ...@@ -1154,6 +1153,9 @@ struct i915_psr {
bool psr2_support; bool psr2_support;
bool aux_frame_sync; bool aux_frame_sync;
bool link_standby; bool link_standby;
bool y_cord_support;
bool colorimetry_support;
bool alpm;
}; };
enum intel_pch { enum intel_pch {
...@@ -1809,6 +1811,7 @@ struct intel_pipe_crc { ...@@ -1809,6 +1811,7 @@ struct intel_pipe_crc {
enum intel_pipe_crc_source source; enum intel_pipe_crc_source source;
int head, tail; int head, tail;
wait_queue_head_t wq; wait_queue_head_t wq;
int skipped;
}; };
struct i915_frontbuffer_tracking { struct i915_frontbuffer_tracking {
...@@ -2069,6 +2072,7 @@ struct drm_i915_private { ...@@ -2069,6 +2072,7 @@ struct drm_i915_private {
struct intel_gvt *gvt; struct intel_gvt *gvt;
struct intel_huc huc;
struct intel_guc guc; struct intel_guc guc;
struct intel_csr csr; struct intel_csr csr;
...@@ -2843,6 +2847,7 @@ intel_info(const struct drm_i915_private *dev_priv) ...@@ -2843,6 +2847,7 @@ intel_info(const struct drm_i915_private *dev_priv)
#define HAS_GUC(dev_priv) ((dev_priv)->info.has_guc) #define HAS_GUC(dev_priv) ((dev_priv)->info.has_guc)
#define HAS_GUC_UCODE(dev_priv) (HAS_GUC(dev_priv)) #define HAS_GUC_UCODE(dev_priv) (HAS_GUC(dev_priv))
#define HAS_GUC_SCHED(dev_priv) (HAS_GUC(dev_priv)) #define HAS_GUC_SCHED(dev_priv) (HAS_GUC(dev_priv))
#define HAS_HUC_UCODE(dev_priv) (HAS_GUC(dev_priv))
#define HAS_RESOURCE_STREAMER(dev_priv) ((dev_priv)->info.has_resource_streamer) #define HAS_RESOURCE_STREAMER(dev_priv) ((dev_priv)->info.has_resource_streamer)
...@@ -3101,9 +3106,9 @@ int i915_gem_throttle_ioctl(struct drm_device *dev, void *data, ...@@ -3101,9 +3106,9 @@ int i915_gem_throttle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_madvise_ioctl(struct drm_device *dev, void *data, int i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_set_tiling(struct drm_device *dev, void *data, int i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
int i915_gem_get_tiling(struct drm_device *dev, void *data, int i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
void i915_gem_init_userptr(struct drm_i915_private *dev_priv); void i915_gem_init_userptr(struct drm_i915_private *dev_priv);
int i915_gem_userptr_ioctl(struct drm_device *dev, void *data, int i915_gem_userptr_ioctl(struct drm_device *dev, void *data,
...@@ -3323,7 +3328,7 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error) ...@@ -3323,7 +3328,7 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error)
return READ_ONCE(error->reset_count); return READ_ONCE(error->reset_count);
} }
void i915_gem_reset_prepare(struct drm_i915_private *dev_priv); int i915_gem_reset_prepare(struct drm_i915_private *dev_priv);
void i915_gem_reset_finish(struct drm_i915_private *dev_priv); void i915_gem_reset_finish(struct drm_i915_private *dev_priv);
void i915_gem_set_wedged(struct drm_i915_private *dev_priv); void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
void i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force); void i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
...@@ -3360,11 +3365,6 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, ...@@ -3360,11 +3365,6 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj,
int i915_gem_open(struct drm_device *dev, struct drm_file *file); int i915_gem_open(struct drm_device *dev, struct drm_file *file);
void i915_gem_release(struct drm_device *dev, struct drm_file *file); void i915_gem_release(struct drm_device *dev, struct drm_file *file);
u64 i915_gem_get_ggtt_size(struct drm_i915_private *dev_priv, u64 size,
int tiling_mode);
u64 i915_gem_get_ggtt_alignment(struct drm_i915_private *dev_priv, u64 size,
int tiling_mode, bool fenced);
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level); enum i915_cache_level cache_level);
...@@ -3374,36 +3374,12 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, ...@@ -3374,36 +3374,12 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *gem_obj, int flags); struct drm_gem_object *gem_obj, int flags);
struct i915_vma *
i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);
struct i915_vma *
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
const struct i915_ggtt_view *view);
static inline struct i915_hw_ppgtt * static inline struct i915_hw_ppgtt *
i915_vm_to_ppgtt(struct i915_address_space *vm) i915_vm_to_ppgtt(struct i915_address_space *vm)
{ {
return container_of(vm, struct i915_hw_ppgtt, base); return container_of(vm, struct i915_hw_ppgtt, base);
} }
static inline struct i915_vma *
i915_gem_object_to_ggtt(struct drm_i915_gem_object *obj,
const struct i915_ggtt_view *view)
{
return i915_gem_obj_to_vma(obj, &to_i915(obj->base.dev)->ggtt.base, view);
}
static inline unsigned long
i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
const struct i915_ggtt_view *view)
{
return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view));
}
/* i915_gem_fence_reg.c */ /* i915_gem_fence_reg.c */
int __must_check i915_vma_get_fence(struct i915_vma *vma); int __must_check i915_vma_get_fence(struct i915_vma *vma);
int __must_check i915_vma_put_fence(struct i915_vma *vma); int __must_check i915_vma_put_fence(struct i915_vma *vma);
...@@ -3471,7 +3447,8 @@ int __must_check i915_gem_evict_something(struct i915_address_space *vm, ...@@ -3471,7 +3447,8 @@ int __must_check i915_gem_evict_something(struct i915_address_space *vm,
unsigned cache_level, unsigned cache_level,
u64 start, u64 end, u64 start, u64 end,
unsigned flags); unsigned flags);
int __must_check i915_gem_evict_for_vma(struct i915_vma *vma, int __must_check i915_gem_evict_for_node(struct i915_address_space *vm,
struct drm_mm_node *node,
unsigned int flags); unsigned int flags);
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle); int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
...@@ -3506,7 +3483,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ...@@ -3506,7 +3483,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
/* i915_gem_internal.c */ /* i915_gem_internal.c */
struct drm_i915_gem_object * struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *dev_priv, i915_gem_object_create_internal(struct drm_i915_private *dev_priv,
unsigned int size); phys_addr_t size);
/* i915_gem_shrinker.c */ /* i915_gem_shrinker.c */
unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv, unsigned long i915_gem_shrink(struct drm_i915_private *dev_priv,
...@@ -3531,6 +3508,11 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec ...@@ -3531,6 +3508,11 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec
i915_gem_object_is_tiled(obj); i915_gem_object_is_tiled(obj);
} }
u32 i915_gem_fence_size(struct drm_i915_private *dev_priv, u32 size,
unsigned int tiling, unsigned int stride);
u32 i915_gem_fence_alignment(struct drm_i915_private *dev_priv, u32 size,
unsigned int tiling, unsigned int stride);
/* i915_debugfs.c */ /* i915_debugfs.c */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
int i915_debugfs_register(struct drm_i915_private *dev_priv); int i915_debugfs_register(struct drm_i915_private *dev_priv);
......
...@@ -1696,12 +1696,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, ...@@ -1696,12 +1696,7 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
static unsigned int tile_row_pages(struct drm_i915_gem_object *obj) static unsigned int tile_row_pages(struct drm_i915_gem_object *obj)
{ {
u64 size; return i915_gem_object_get_tile_row_size(obj) >> PAGE_SHIFT;
size = i915_gem_object_get_stride(obj);
size *= i915_gem_object_get_tiling(obj) == I915_TILING_Y ? 32 : 8;
return size >> PAGE_SHIFT;
} }
/** /**
...@@ -1754,6 +1749,29 @@ int i915_gem_mmap_gtt_version(void) ...@@ -1754,6 +1749,29 @@ int i915_gem_mmap_gtt_version(void)
return 1; return 1;
} }
static inline struct i915_ggtt_view
compute_partial_view(struct drm_i915_gem_object *obj,
pgoff_t page_offset,
unsigned int chunk)
{
struct i915_ggtt_view view;
if (i915_gem_object_is_tiled(obj))
chunk = roundup(chunk, tile_row_pages(obj));
view.type = I915_GGTT_VIEW_PARTIAL;
view.partial.offset = rounddown(page_offset, chunk);
view.partial.size =
min_t(unsigned int, chunk,
(obj->base.size >> PAGE_SHIFT) - view.partial.offset);
/* If the partial covers the entire object, just create a normal VMA. */
if (chunk >= obj->base.size >> PAGE_SHIFT)
view.type = I915_GGTT_VIEW_NORMAL;
return view;
}
/** /**
* i915_gem_fault - fault a page into the GTT * i915_gem_fault - fault a page into the GTT
* @area: CPU VMA in question * @area: CPU VMA in question
...@@ -1830,26 +1848,9 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf) ...@@ -1830,26 +1848,9 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
/* Now pin it into the GTT as needed */ /* Now pin it into the GTT as needed */
vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, flags); vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, flags);
if (IS_ERR(vma)) { if (IS_ERR(vma)) {
struct i915_ggtt_view view;
unsigned int chunk_size;
/* Use a partial view if it is bigger than available space */ /* Use a partial view if it is bigger than available space */
chunk_size = MIN_CHUNK_PAGES; struct i915_ggtt_view view =
if (i915_gem_object_is_tiled(obj)) compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
chunk_size = roundup(chunk_size, tile_row_pages(obj));
memset(&view, 0, sizeof(view));
view.type = I915_GGTT_VIEW_PARTIAL;
view.params.partial.offset = rounddown(page_offset, chunk_size);
view.params.partial.size =
min_t(unsigned int, chunk_size,
vma_pages(area) - view.params.partial.offset);
/* If the partial covers the entire object, just create a
* normal VMA.
*/
if (chunk_size >= obj->base.size >> PAGE_SHIFT)
view.type = I915_GGTT_VIEW_NORMAL;
/* Userspace is now writing through an untracked VMA, abandon /* Userspace is now writing through an untracked VMA, abandon
* all hope that the hardware is able to track future writes. * all hope that the hardware is able to track future writes.
...@@ -1878,7 +1879,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf) ...@@ -1878,7 +1879,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
/* Finally, remap it using the new GTT offset */ /* Finally, remap it using the new GTT offset */
ret = remap_io_mapping(area, ret = remap_io_mapping(area,
area->vm_start + (vma->ggtt_view.params.partial.offset << PAGE_SHIFT), area->vm_start + (vma->ggtt_view.partial.offset << PAGE_SHIFT),
(ggtt->mappable_base + vma->node.start) >> PAGE_SHIFT, (ggtt->mappable_base + vma->node.start) >> PAGE_SHIFT,
min_t(u64, vma->size, area->vm_end - area->vm_start), min_t(u64, vma->size, area->vm_end - area->vm_start),
&ggtt->mappable); &ggtt->mappable);
...@@ -2021,69 +2022,6 @@ void i915_gem_runtime_suspend(struct drm_i915_private *dev_priv) ...@@ -2021,69 +2022,6 @@ void i915_gem_runtime_suspend(struct drm_i915_private *dev_priv)
} }
} }
/**
* i915_gem_get_ggtt_size - return required global GTT size for an object
* @dev_priv: i915 device
* @size: object size
* @tiling_mode: tiling mode
*
* Return the required global GTT size for an object, taking into account
* potential fence register mapping.
*/
u64 i915_gem_get_ggtt_size(struct drm_i915_private *dev_priv,
u64 size, int tiling_mode)
{
u64 ggtt_size;
GEM_BUG_ON(size == 0);
if (INTEL_GEN(dev_priv) >= 4 ||
tiling_mode == I915_TILING_NONE)
return size;
/* Previous chips need a power-of-two fence region when tiling */
if (IS_GEN3(dev_priv))
ggtt_size = 1024*1024;
else
ggtt_size = 512*1024;
while (ggtt_size < size)
ggtt_size <<= 1;
return ggtt_size;
}
/**
* i915_gem_get_ggtt_alignment - return required global GTT alignment
* @dev_priv: i915 device
* @size: object size
* @tiling_mode: tiling mode
* @fenced: is fenced alignment required or not
*
* Return the required global GTT alignment for an object, taking into account
* potential fence register mapping.
*/
u64 i915_gem_get_ggtt_alignment(struct drm_i915_private *dev_priv, u64 size,
int tiling_mode, bool fenced)
{
GEM_BUG_ON(size == 0);
/*
* Minimum alignment is 4k (GTT page size), but might be greater
* if a fence register is needed for the object.
*/
if (INTEL_GEN(dev_priv) >= 4 ||
(!fenced && (IS_G33(dev_priv) || IS_PINEVIEW(dev_priv))) ||
tiling_mode == I915_TILING_NONE)
return 4096;
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object.
*/
return i915_gem_get_ggtt_size(dev_priv, size, tiling_mode);
}
static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj) static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
{ {
struct drm_i915_private *dev_priv = to_i915(obj->base.dev); struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
...@@ -2666,13 +2604,52 @@ i915_gem_find_active_request(struct intel_engine_cs *engine) ...@@ -2666,13 +2604,52 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
if (__i915_gem_request_completed(request)) if (__i915_gem_request_completed(request))
continue; continue;
GEM_BUG_ON(request->engine != engine);
return request; return request;
} }
return NULL; return NULL;
} }
static void reset_request(struct drm_i915_gem_request *request) static bool engine_stalled(struct intel_engine_cs *engine)
{
if (!engine->hangcheck.stalled)
return false;
/* Check for possible seqno movement after hang declaration */
if (engine->hangcheck.seqno != intel_engine_get_seqno(engine)) {
DRM_DEBUG_DRIVER("%s pardoned\n", engine->name);
return false;
}
return true;
}
int i915_gem_reset_prepare(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
int err = 0;
/* Ensure irq handler finishes, and not run again. */
for_each_engine(engine, dev_priv, id) {
struct drm_i915_gem_request *request;
tasklet_kill(&engine->irq_tasklet);
if (engine_stalled(engine)) {
request = i915_gem_find_active_request(engine);
if (request && request->fence.error == -EIO)
err = -EIO; /* Previous reset failed! */
}
}
i915_gem_revoke_fences(dev_priv);
return err;
}
static void skip_request(struct drm_i915_gem_request *request)
{ {
void *vaddr = request->ring->vaddr; void *vaddr = request->ring->vaddr;
u32 head; u32 head;
...@@ -2687,20 +2664,74 @@ static void reset_request(struct drm_i915_gem_request *request) ...@@ -2687,20 +2664,74 @@ static void reset_request(struct drm_i915_gem_request *request)
head = 0; head = 0;
} }
memset(vaddr + head, 0, request->postfix - head); memset(vaddr + head, 0, request->postfix - head);
dma_fence_set_error(&request->fence, -EIO);
} }
void i915_gem_reset_prepare(struct drm_i915_private *dev_priv) static void engine_skip_context(struct drm_i915_gem_request *request)
{ {
i915_gem_revoke_fences(dev_priv); struct intel_engine_cs *engine = request->engine;
struct i915_gem_context *hung_ctx = request->ctx;
struct intel_timeline *timeline;
unsigned long flags;
timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
spin_lock_irqsave(&engine->timeline->lock, flags);
spin_lock(&timeline->lock);
list_for_each_entry_continue(request, &engine->timeline->requests, link)
if (request->ctx == hung_ctx)
skip_request(request);
list_for_each_entry(request, &timeline->requests, link)
skip_request(request);
spin_unlock(&timeline->lock);
spin_unlock_irqrestore(&engine->timeline->lock, flags);
}
/* Returns true if the request was guilty of hang */
static bool i915_gem_reset_request(struct drm_i915_gem_request *request)
{
/* Read once and return the resolution */
const bool guilty = engine_stalled(request->engine);
/* The guilty request will get skipped on a hung engine.
*
* Users of client default contexts do not rely on logical
* state preserved between batches so it is safe to execute
* queued requests following the hang. Non default contexts
* rely on preserved state, so skipping a batch loses the
* evolution of the state and it needs to be considered corrupted.
* Executing more queued batches on top of corrupted state is
* risky. But we take the risk by trying to advance through
* the queued requests in order to make the client behaviour
* more predictable around resets, by not throwing away random
* amount of batches it has prepared for execution. Sophisticated
* clients can use gem_reset_stats_ioctl and dma fence status
* (exported via sync_file info ioctl on explicit fences) to observe
* when it loses the context state and should rebuild accordingly.
*
* The context ban, and ultimately the client ban, mechanism are safety
* valves if client submission ends up resulting in nothing more than
* subsequent hangs.
*/
if (guilty) {
i915_gem_context_mark_guilty(request->ctx);
skip_request(request);
} else {
i915_gem_context_mark_innocent(request->ctx);
dma_fence_set_error(&request->fence, -EAGAIN);
}
return guilty;
} }
static void i915_gem_reset_engine(struct intel_engine_cs *engine) static void i915_gem_reset_engine(struct intel_engine_cs *engine)
{ {
struct drm_i915_gem_request *request; struct drm_i915_gem_request *request;
struct i915_gem_context *hung_ctx;
struct intel_timeline *timeline;
unsigned long flags;
bool ring_hung;
if (engine->irq_seqno_barrier) if (engine->irq_seqno_barrier)
engine->irq_seqno_barrier(engine); engine->irq_seqno_barrier(engine);
...@@ -2709,22 +2740,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine) ...@@ -2709,22 +2740,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
if (!request) if (!request)
return; return;
hung_ctx = request->ctx; if (!i915_gem_reset_request(request))
ring_hung = engine->hangcheck.stalled;
if (engine->hangcheck.seqno != intel_engine_get_seqno(engine)) {
DRM_DEBUG_DRIVER("%s pardoned, was guilty? %s\n",
engine->name,
yesno(ring_hung));
ring_hung = false;
}
if (ring_hung)
i915_gem_context_mark_guilty(hung_ctx);
else
i915_gem_context_mark_innocent(hung_ctx);
if (!ring_hung)
return; return;
DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n", DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n",
...@@ -2734,34 +2750,8 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine) ...@@ -2734,34 +2750,8 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
engine->reset_hw(engine, request); engine->reset_hw(engine, request);
/* If this context is now banned, skip all of its pending requests. */ /* If this context is now banned, skip all of its pending requests. */
if (!i915_gem_context_is_banned(hung_ctx)) if (i915_gem_context_is_banned(request->ctx))
return; engine_skip_context(request);
/* Users of the default context do not rely on logical state
* preserved between batches. They have to emit full state on
* every batch and so it is safe to execute queued requests following
* the hang.
*
* Other contexts preserve state, now corrupt. We want to skip all
* queued requests that reference the corrupt context.
*/
if (i915_gem_context_is_default(hung_ctx))
return;
timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
spin_lock_irqsave(&engine->timeline->lock, flags);
spin_lock(&timeline->lock);
list_for_each_entry_continue(request, &engine->timeline->requests, link)
if (request->ctx == hung_ctx)
reset_request(request);
list_for_each_entry(request, &timeline->requests, link)
reset_request(request);
spin_unlock(&timeline->lock);
spin_unlock_irqrestore(&engine->timeline->lock, flags);
} }
void i915_gem_reset_finish(struct drm_i915_private *dev_priv) void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
...@@ -2788,12 +2778,16 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv) ...@@ -2788,12 +2778,16 @@ void i915_gem_reset_finish(struct drm_i915_private *dev_priv)
static void nop_submit_request(struct drm_i915_gem_request *request) static void nop_submit_request(struct drm_i915_gem_request *request)
{ {
dma_fence_set_error(&request->fence, -EIO);
i915_gem_request_submit(request); i915_gem_request_submit(request);
intel_engine_init_global_seqno(request->engine, request->global_seqno); intel_engine_init_global_seqno(request->engine, request->global_seqno);
} }
static void i915_gem_cleanup_engine(struct intel_engine_cs *engine) static void engine_set_wedged(struct intel_engine_cs *engine)
{ {
struct drm_i915_gem_request *request;
unsigned long flags;
/* We need to be sure that no thread is running the old callback as /* We need to be sure that no thread is running the old callback as
* we install the nop handler (otherwise we would submit a request * we install the nop handler (otherwise we would submit a request
* to hardware that will never complete). In order to prevent this * to hardware that will never complete). In order to prevent this
...@@ -2802,6 +2796,12 @@ static void i915_gem_cleanup_engine(struct intel_engine_cs *engine) ...@@ -2802,6 +2796,12 @@ static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
*/ */
engine->submit_request = nop_submit_request; engine->submit_request = nop_submit_request;
/* Mark all executing requests as skipped */
spin_lock_irqsave(&engine->timeline->lock, flags);
list_for_each_entry(request, &engine->timeline->requests, link)
dma_fence_set_error(&request->fence, -EIO);
spin_unlock_irqrestore(&engine->timeline->lock, flags);
/* Mark all pending requests as complete so that any concurrent /* Mark all pending requests as complete so that any concurrent
* (lockless) lookup doesn't try and wait upon the request as we * (lockless) lookup doesn't try and wait upon the request as we
* reset it. * reset it.
...@@ -2837,7 +2837,7 @@ static int __i915_gem_set_wedged_BKL(void *data) ...@@ -2837,7 +2837,7 @@ static int __i915_gem_set_wedged_BKL(void *data)
enum intel_engine_id id; enum intel_engine_id id;
for_each_engine(engine, i915, id) for_each_engine(engine, i915, id)
i915_gem_cleanup_engine(engine); engine_set_wedged(engine);
return 0; return 0;
} }
...@@ -3397,7 +3397,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, ...@@ -3397,7 +3397,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_caching *args = data; struct drm_i915_gem_caching *args = data;
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
enum i915_cache_level level; enum i915_cache_level level;
int ret; int ret = 0;
switch (args->caching) { switch (args->caching) {
case I915_CACHING_NONE: case I915_CACHING_NONE:
...@@ -3422,20 +3422,29 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, ...@@ -3422,20 +3422,29 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
return -EINVAL; return -EINVAL;
} }
ret = i915_mutex_lock_interruptible(dev); obj = i915_gem_object_lookup(file, args->handle);
if (!obj)
return -ENOENT;
if (obj->cache_level == level)
goto out;
ret = i915_gem_object_wait(obj,
I915_WAIT_INTERRUPTIBLE,
MAX_SCHEDULE_TIMEOUT,
to_rps_client(file));
if (ret) if (ret)
return ret; goto out;
obj = i915_gem_object_lookup(file, args->handle); ret = i915_mutex_lock_interruptible(dev);
if (!obj) { if (ret)
ret = -ENOENT; goto out;
goto unlock;
}
ret = i915_gem_object_set_cache_level(obj, level); ret = i915_gem_object_set_cache_level(obj, level);
i915_gem_object_put(obj);
unlock:
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
out:
i915_gem_object_put(obj);
return ret; return ret;
} }
...@@ -3485,7 +3494,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, ...@@ -3485,7 +3494,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
* try to preserve the existing ABI). * try to preserve the existing ABI).
*/ */
vma = ERR_PTR(-ENOSPC); vma = ERR_PTR(-ENOSPC);
if (view->type == I915_GGTT_VIEW_NORMAL) if (!view || view->type == I915_GGTT_VIEW_NORMAL)
vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment, vma = i915_gem_object_ggtt_pin(obj, view, 0, alignment,
PIN_MAPPABLE | PIN_NONBLOCK); PIN_MAPPABLE | PIN_NONBLOCK);
if (IS_ERR(vma)) { if (IS_ERR(vma)) {
...@@ -3544,11 +3553,10 @@ i915_gem_object_unpin_from_display_plane(struct i915_vma *vma) ...@@ -3544,11 +3553,10 @@ i915_gem_object_unpin_from_display_plane(struct i915_vma *vma)
return; return;
if (--vma->obj->pin_display == 0) if (--vma->obj->pin_display == 0)
vma->display_alignment = 0; vma->display_alignment = I915_GTT_MIN_ALIGNMENT;
/* Bump the LRU to try and avoid premature eviction whilst flipping */ /* Bump the LRU to try and avoid premature eviction whilst flipping */
if (!i915_vma_is_active(vma)) i915_gem_object_bump_inactive_ggtt(vma->obj);
list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
i915_vma_unpin(vma); i915_vma_unpin(vma);
} }
...@@ -3679,8 +3687,8 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, ...@@ -3679,8 +3687,8 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
lockdep_assert_held(&obj->base.dev->struct_mutex); lockdep_assert_held(&obj->base.dev->struct_mutex);
vma = i915_gem_obj_lookup_or_create_vma(obj, vm, view); vma = i915_vma_instance(obj, vm, view);
if (IS_ERR(vma)) if (unlikely(IS_ERR(vma)))
return vma; return vma;
if (i915_vma_misplaced(vma, size, alignment, flags)) { if (i915_vma_misplaced(vma, size, alignment, flags)) {
...@@ -3689,10 +3697,6 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, ...@@ -3689,10 +3697,6 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
return ERR_PTR(-ENOSPC); return ERR_PTR(-ENOSPC);
if (flags & PIN_MAPPABLE) { if (flags & PIN_MAPPABLE) {
u32 fence_size;
fence_size = i915_gem_get_ggtt_size(dev_priv, vma->size,
i915_gem_object_get_tiling(obj));
/* If the required space is larger than the available /* If the required space is larger than the available
* aperture, we will not able to find a slot for the * aperture, we will not able to find a slot for the
* object and unbinding the object now will be in * object and unbinding the object now will be in
...@@ -3700,7 +3704,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, ...@@ -3700,7 +3704,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
* the object in and out of the Global GTT and * the object in and out of the Global GTT and
* waste a lot of cycles under the mutex. * waste a lot of cycles under the mutex.
*/ */
if (fence_size > dev_priv->ggtt.mappable_end) if (vma->fence_size > dev_priv->ggtt.mappable_end)
return ERR_PTR(-E2BIG); return ERR_PTR(-E2BIG);
/* If NONBLOCK is set the caller is optimistically /* If NONBLOCK is set the caller is optimistically
...@@ -3719,7 +3723,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj, ...@@ -3719,7 +3723,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
* we could try to minimise harm to others. * we could try to minimise harm to others.
*/ */
if (flags & PIN_NONBLOCK && if (flags & PIN_NONBLOCK &&
fence_size > dev_priv->ggtt.mappable_end / 2) vma->fence_size > dev_priv->ggtt.mappable_end / 2)
return ERR_PTR(-ENOSPC); return ERR_PTR(-ENOSPC);
} }
...@@ -4193,7 +4197,8 @@ static void assert_kernel_context_is_current(struct drm_i915_private *dev_priv) ...@@ -4193,7 +4197,8 @@ static void assert_kernel_context_is_current(struct drm_i915_private *dev_priv)
enum intel_engine_id id; enum intel_engine_id id;
for_each_engine(engine, dev_priv, id) for_each_engine(engine, dev_priv, id)
GEM_BUG_ON(!i915_gem_context_is_kernel(engine->last_retired_context)); GEM_BUG_ON(engine->last_retired_context &&
!i915_gem_context_is_kernel(engine->last_retired_context));
} }
int i915_gem_suspend(struct drm_i915_private *dev_priv) int i915_gem_suspend(struct drm_i915_private *dev_priv)
......
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
* part. It should be safe to decrease this, but it's more future proof as is. * part. It should be safe to decrease this, but it's more future proof as is.
*/ */
#define GEN6_CONTEXT_ALIGN (64<<10) #define GEN6_CONTEXT_ALIGN (64<<10)
#define GEN7_CONTEXT_ALIGN 4096 #define GEN7_CONTEXT_ALIGN I915_GTT_MIN_ALIGNMENT
static size_t get_context_alignment(struct drm_i915_private *dev_priv) static size_t get_context_alignment(struct drm_i915_private *dev_priv)
{ {
...@@ -205,27 +205,6 @@ alloc_context_obj(struct drm_i915_private *dev_priv, u64 size) ...@@ -205,27 +205,6 @@ alloc_context_obj(struct drm_i915_private *dev_priv, u64 size)
return obj; return obj;
} }
static void i915_ppgtt_close(struct i915_address_space *vm)
{
struct list_head *phases[] = {
&vm->active_list,
&vm->inactive_list,
&vm->unbound_list,
NULL,
}, **phase;
GEM_BUG_ON(vm->closed);
vm->closed = true;
for (phase = phases; *phase; phase++) {
struct i915_vma *vma, *vn;
list_for_each_entry_safe(vma, vn, *phase, vm_link)
if (!i915_vma_is_closed(vma))
i915_vma_close(vma);
}
}
static void context_close(struct i915_gem_context *ctx) static void context_close(struct i915_gem_context *ctx)
{ {
i915_gem_context_set_closed(ctx); i915_gem_context_set_closed(ctx);
...@@ -290,7 +269,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, ...@@ -290,7 +269,7 @@ __create_hw_context(struct drm_i915_private *dev_priv,
goto err_out; goto err_out;
} }
vma = i915_vma_create(obj, &dev_priv->ggtt.base, NULL); vma = i915_vma_instance(obj, &dev_priv->ggtt.base, NULL);
if (IS_ERR(vma)) { if (IS_ERR(vma)) {
i915_gem_object_put(obj); i915_gem_object_put(obj);
ret = PTR_ERR(vma); ret = PTR_ERR(vma);
...@@ -341,7 +320,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, ...@@ -341,7 +320,7 @@ __create_hw_context(struct drm_i915_private *dev_priv,
if (HAS_GUC(dev_priv) && i915.enable_guc_loading) if (HAS_GUC(dev_priv) && i915.enable_guc_loading)
ctx->ggtt_offset_bias = GUC_WOPCM_TOP; ctx->ggtt_offset_bias = GUC_WOPCM_TOP;
else else
ctx->ggtt_offset_bias = 4096; ctx->ggtt_offset_bias = I915_GTT_PAGE_SIZE;
return ctx; return ctx;
...@@ -456,7 +435,8 @@ int i915_gem_context_init(struct drm_i915_private *dev_priv) ...@@ -456,7 +435,8 @@ int i915_gem_context_init(struct drm_i915_private *dev_priv)
dev_priv->hw_context_size = 0; dev_priv->hw_context_size = 0;
} else if (HAS_HW_CONTEXTS(dev_priv)) { } else if (HAS_HW_CONTEXTS(dev_priv)) {
dev_priv->hw_context_size = dev_priv->hw_context_size =
round_up(get_context_size(dev_priv), 4096); round_up(get_context_size(dev_priv),
I915_GTT_PAGE_SIZE);
if (dev_priv->hw_context_size > (1<<20)) { if (dev_priv->hw_context_size > (1<<20)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n", DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
dev_priv->hw_context_size); dev_priv->hw_context_size);
...@@ -897,6 +877,26 @@ int i915_switch_context(struct drm_i915_gem_request *req) ...@@ -897,6 +877,26 @@ int i915_switch_context(struct drm_i915_gem_request *req)
return do_rcs_switch(req); return do_rcs_switch(req);
} }
static bool engine_has_kernel_context(struct intel_engine_cs *engine)
{
struct i915_gem_timeline *timeline;
list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
struct intel_timeline *tl;
if (timeline == &engine->i915->gt.global_timeline)
continue;
tl = &timeline->engine[engine->id];
if (i915_gem_active_peek(&tl->last_request,
&engine->i915->drm.struct_mutex))
return false;
}
return (!engine->last_retired_context ||
i915_gem_context_is_kernel(engine->last_retired_context));
}
int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv) int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
{ {
struct intel_engine_cs *engine; struct intel_engine_cs *engine;
...@@ -905,10 +905,15 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv) ...@@ -905,10 +905,15 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
lockdep_assert_held(&dev_priv->drm.struct_mutex); lockdep_assert_held(&dev_priv->drm.struct_mutex);
i915_gem_retire_requests(dev_priv);
for_each_engine(engine, dev_priv, id) { for_each_engine(engine, dev_priv, id) {
struct drm_i915_gem_request *req; struct drm_i915_gem_request *req;
int ret; int ret;
if (engine_has_kernel_context(engine))
continue;
req = i915_gem_request_alloc(engine, dev_priv->kernel_context); req = i915_gem_request_alloc(engine, dev_priv->kernel_context);
if (IS_ERR(req)) if (IS_ERR(req))
return PTR_ERR(req); return PTR_ERR(req);
......
...@@ -231,7 +231,8 @@ i915_gem_evict_something(struct i915_address_space *vm, ...@@ -231,7 +231,8 @@ i915_gem_evict_something(struct i915_address_space *vm,
/** /**
* i915_gem_evict_for_vma - Evict vmas to make room for binding a new one * i915_gem_evict_for_vma - Evict vmas to make room for binding a new one
* @target: address space and range to evict for * @vm: address space to evict from
* @target: range (and color) to evict for
* @flags: additional flags to control the eviction algorithm * @flags: additional flags to control the eviction algorithm
* *
* This function will try to evict vmas that overlap the target node. * This function will try to evict vmas that overlap the target node.
...@@ -239,18 +240,20 @@ i915_gem_evict_something(struct i915_address_space *vm, ...@@ -239,18 +240,20 @@ i915_gem_evict_something(struct i915_address_space *vm,
* To clarify: This is for freeing up virtual address space, not for freeing * To clarify: This is for freeing up virtual address space, not for freeing
* memory in e.g. the shrinker. * memory in e.g. the shrinker.
*/ */
int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags) int i915_gem_evict_for_node(struct i915_address_space *vm,
struct drm_mm_node *target,
unsigned int flags)
{ {
LIST_HEAD(eviction_list); LIST_HEAD(eviction_list);
struct drm_mm_node *node; struct drm_mm_node *node;
u64 start = target->node.start; u64 start = target->start;
u64 end = start + target->node.size; u64 end = start + target->size;
struct i915_vma *vma, *next; struct i915_vma *vma, *next;
bool check_color; bool check_color;
int ret = 0; int ret = 0;
lockdep_assert_held(&target->vm->i915->drm.struct_mutex); lockdep_assert_held(&vm->i915->drm.struct_mutex);
trace_i915_gem_evict_vma(target, flags); trace_i915_gem_evict_node(vm, target, flags);
/* Retire before we search the active list. Although we have /* Retire before we search the active list. Although we have
* reasonable accuracy in our retirement lists, we may have * reasonable accuracy in our retirement lists, we may have
...@@ -258,18 +261,18 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags) ...@@ -258,18 +261,18 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
* retiring. * retiring.
*/ */
if (!(flags & PIN_NONBLOCK)) if (!(flags & PIN_NONBLOCK))
i915_gem_retire_requests(target->vm->i915); i915_gem_retire_requests(vm->i915);
check_color = target->vm->mm.color_adjust; check_color = vm->mm.color_adjust;
if (check_color) { if (check_color) {
/* Expand search to cover neighbouring guard pages (or lack!) */ /* Expand search to cover neighbouring guard pages (or lack!) */
if (start > target->vm->start) if (start > vm->start)
start -= 4096; start -= I915_GTT_PAGE_SIZE;
if (end < target->vm->start + target->vm->total) if (end < vm->start + vm->total)
end += 4096; end += I915_GTT_PAGE_SIZE;
} }
drm_mm_for_each_node_in_range(node, &target->vm->mm, start, end) { drm_mm_for_each_node_in_range(node, &vm->mm, start, end) {
/* If we find any non-objects (!vma), we cannot evict them */ /* If we find any non-objects (!vma), we cannot evict them */
if (node->color == I915_COLOR_UNEVICTABLE) { if (node->color == I915_COLOR_UNEVICTABLE) {
ret = -ENOSPC; ret = -ENOSPC;
...@@ -285,12 +288,12 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags) ...@@ -285,12 +288,12 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
* those as well to make room for our guard pages. * those as well to make room for our guard pages.
*/ */
if (check_color) { if (check_color) {
if (vma->node.start + vma->node.size == target->node.start) { if (vma->node.start + vma->node.size == node->start) {
if (vma->node.color == target->node.color) if (vma->node.color == node->color)
continue; continue;
} }
if (vma->node.start == target->node.start + target->node.size) { if (vma->node.start == node->start + node->size) {
if (vma->node.color == target->node.color) if (vma->node.color == node->color)
continue; continue;
} }
} }
...@@ -302,7 +305,7 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags) ...@@ -302,7 +305,7 @@ int i915_gem_evict_for_vma(struct i915_vma *target, unsigned int flags)
} }
/* Overlap of objects in the same batch? */ /* Overlap of objects in the same batch? */
if (i915_vma_is_pinned(vma)) { if (i915_vma_is_pinned(vma) || !list_empty(&vma->exec_list)) {
ret = -ENOSPC; ret = -ENOSPC;
if (vma->exec_entry && if (vma->exec_entry &&
vma->exec_entry->flags & EXEC_OBJECT_PINNED) vma->exec_entry->flags & EXEC_OBJECT_PINNED)
......
...@@ -184,7 +184,7 @@ eb_lookup_vmas(struct eb_vmas *eb, ...@@ -184,7 +184,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
* from the (obj, vm) we don't run the risk of creating * from the (obj, vm) we don't run the risk of creating
* duplicated vmas for the same vm. * duplicated vmas for the same vm.
*/ */
vma = i915_gem_obj_lookup_or_create_vma(obj, vm, NULL); vma = i915_vma_instance(obj, vm, NULL);
if (unlikely(IS_ERR(vma))) { if (unlikely(IS_ERR(vma))) {
DRM_DEBUG("Failed to lookup VMA\n"); DRM_DEBUG("Failed to lookup VMA\n");
ret = PTR_ERR(vma); ret = PTR_ERR(vma);
...@@ -438,7 +438,7 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj, ...@@ -438,7 +438,7 @@ static void *reloc_iomap(struct drm_i915_gem_object *obj,
memset(&cache->node, 0, sizeof(cache->node)); memset(&cache->node, 0, sizeof(cache->node));
ret = drm_mm_insert_node_in_range_generic ret = drm_mm_insert_node_in_range_generic
(&ggtt->base.mm, &cache->node, (&ggtt->base.mm, &cache->node,
4096, 0, I915_COLOR_UNEVICTABLE, PAGE_SIZE, 0, I915_COLOR_UNEVICTABLE,
0, ggtt->mappable_end, 0, ggtt->mappable_end,
DRM_MM_SEARCH_DEFAULT, DRM_MM_SEARCH_DEFAULT,
DRM_MM_CREATE_DEFAULT); DRM_MM_CREATE_DEFAULT);
...@@ -851,8 +851,7 @@ eb_vma_misplaced(struct i915_vma *vma) ...@@ -851,8 +851,7 @@ eb_vma_misplaced(struct i915_vma *vma)
WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP && WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
!i915_vma_is_ggtt(vma)); !i915_vma_is_ggtt(vma));
if (entry->alignment && if (entry->alignment && !IS_ALIGNED(vma->node.start, entry->alignment))
vma->node.start & (entry->alignment - 1))
return true; return true;
if (vma->node.size < entry->pad_to_size) if (vma->node.size < entry->pad_to_size)
......
...@@ -77,16 +77,17 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *fence, ...@@ -77,16 +77,17 @@ static void i965_write_fence_reg(struct drm_i915_fence_reg *fence,
val = 0; val = 0;
if (vma) { if (vma) {
unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj); unsigned int stride = i915_gem_object_get_stride(vma->obj);
u32 row_size = stride * (is_y_tiled ? 32 : 8);
u32 size = rounddown((u32)vma->node.size, row_size);
val = ((vma->node.start + size - 4096) & 0xfffff000) << 32; GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
val |= vma->node.start & 0xfffff000; GEM_BUG_ON(!IS_ALIGNED(vma->node.start, I965_FENCE_PAGE));
GEM_BUG_ON(!IS_ALIGNED(vma->fence_size, I965_FENCE_PAGE));
GEM_BUG_ON(!IS_ALIGNED(stride, 128));
val = (vma->node.start + vma->fence_size - I965_FENCE_PAGE) << 32;
val |= vma->node.start;
val |= (u64)((stride / 128) - 1) << fence_pitch_shift; val |= (u64)((stride / 128) - 1) << fence_pitch_shift;
if (is_y_tiled) if (i915_gem_object_get_tiling(vma->obj) == I915_TILING_Y)
val |= BIT(I965_FENCE_TILING_Y_SHIFT); val |= BIT(I965_FENCE_TILING_Y_SHIFT);
val |= I965_FENCE_REG_VALID; val |= I965_FENCE_REG_VALID;
} }
...@@ -122,31 +123,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *fence, ...@@ -122,31 +123,24 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *fence,
unsigned int tiling = i915_gem_object_get_tiling(vma->obj); unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
bool is_y_tiled = tiling == I915_TILING_Y; bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj); unsigned int stride = i915_gem_object_get_stride(vma->obj);
int pitch_val;
int tile_width;
WARN((vma->node.start & ~I915_FENCE_START_MASK) || GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
!is_power_of_2(vma->node.size) || GEM_BUG_ON(vma->node.start & ~I915_FENCE_START_MASK);
(vma->node.start & (vma->node.size - 1)), GEM_BUG_ON(!is_power_of_2(vma->fence_size));
"object 0x%08llx [fenceable? %d] not 1M or pot-size (0x%08llx) aligned\n", GEM_BUG_ON(!IS_ALIGNED(vma->node.start, vma->fence_size));
vma->node.start,
i915_vma_is_map_and_fenceable(vma),
vma->node.size);
if (is_y_tiled && HAS_128_BYTE_Y_TILING(fence->i915)) if (is_y_tiled && HAS_128_BYTE_Y_TILING(fence->i915))
tile_width = 128; stride /= 128;
else else
tile_width = 512; stride /= 512;
GEM_BUG_ON(!is_power_of_2(stride));
/* Note: pitch better be a power of two tile widths */
pitch_val = stride / tile_width;
pitch_val = ffs(pitch_val) - 1;
val = vma->node.start; val = vma->node.start;
if (is_y_tiled) if (is_y_tiled)
val |= BIT(I830_FENCE_TILING_Y_SHIFT); val |= BIT(I830_FENCE_TILING_Y_SHIFT);
val |= I915_FENCE_SIZE_BITS(vma->node.size); val |= I915_FENCE_SIZE_BITS(vma->fence_size);
val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= ilog2(stride) << I830_FENCE_PITCH_SHIFT;
val |= I830_FENCE_REG_VALID; val |= I830_FENCE_REG_VALID;
} }
...@@ -166,25 +160,19 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *fence, ...@@ -166,25 +160,19 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *fence,
val = 0; val = 0;
if (vma) { if (vma) {
unsigned int tiling = i915_gem_object_get_tiling(vma->obj);
bool is_y_tiled = tiling == I915_TILING_Y;
unsigned int stride = i915_gem_object_get_stride(vma->obj); unsigned int stride = i915_gem_object_get_stride(vma->obj);
u32 pitch_val;
WARN((vma->node.start & ~I830_FENCE_START_MASK) || GEM_BUG_ON(!i915_vma_is_map_and_fenceable(vma));
!is_power_of_2(vma->node.size) || GEM_BUG_ON(vma->node.start & ~I830_FENCE_START_MASK);
(vma->node.start & (vma->node.size - 1)), GEM_BUG_ON(!is_power_of_2(vma->fence_size));
"object 0x%08llx not 512K or pot-size 0x%08llx aligned\n", GEM_BUG_ON(!is_power_of_2(stride / 128));
vma->node.start, vma->node.size); GEM_BUG_ON(!IS_ALIGNED(vma->node.start, vma->fence_size));
pitch_val = stride / 128;
pitch_val = ffs(pitch_val) - 1;
val = vma->node.start; val = vma->node.start;
if (is_y_tiled) if (i915_gem_object_get_tiling(vma->obj) == I915_TILING_Y)
val |= BIT(I830_FENCE_TILING_Y_SHIFT); val |= BIT(I830_FENCE_TILING_Y_SHIFT);
val |= I830_FENCE_SIZE_BITS(vma->node.size); val |= I830_FENCE_SIZE_BITS(vma->fence_size);
val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= ilog2(stride / 128) << I830_FENCE_PITCH_SHIFT;
val |= I830_FENCE_REG_VALID; val |= I830_FENCE_REG_VALID;
} }
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
struct drm_i915_private; struct drm_i915_private;
struct i915_vma; struct i915_vma;
#define I965_FENCE_PAGE 4096UL
struct drm_i915_fence_reg { struct drm_i915_fence_reg {
struct list_head link; struct list_head link;
struct drm_i915_private *i915; struct drm_i915_private *i915;
......
This diff is collapsed.
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
#include "i915_gem_timeline.h" #include "i915_gem_timeline.h"
#include "i915_gem_request.h" #include "i915_gem_request.h"
#define I915_GTT_PAGE_SIZE 4096UL
#define I915_GTT_MIN_ALIGNMENT I915_GTT_PAGE_SIZE
#define I915_FENCE_REG_NONE -1 #define I915_FENCE_REG_NONE -1
#define I915_MAX_NUM_FENCES 32 #define I915_MAX_NUM_FENCES 32
/* 32 fences + sign bit for FENCE_REG_NONE */ /* 32 fences + sign bit for FENCE_REG_NONE */
...@@ -142,34 +145,57 @@ typedef uint64_t gen8_ppgtt_pml4e_t; ...@@ -142,34 +145,57 @@ typedef uint64_t gen8_ppgtt_pml4e_t;
struct sg_table; struct sg_table;
enum i915_ggtt_view_type {
I915_GGTT_VIEW_NORMAL = 0,
I915_GGTT_VIEW_ROTATED,
I915_GGTT_VIEW_PARTIAL,
};
struct intel_rotation_info { struct intel_rotation_info {
struct { struct intel_rotation_plane_info {
/* tiles */ /* tiles */
unsigned int width, height, stride, offset; unsigned int width, height, stride, offset;
} plane[2]; } plane[2];
} __packed;
static inline void assert_intel_rotation_info_is_packed(void)
{
BUILD_BUG_ON(sizeof(struct intel_rotation_info) != 8*sizeof(unsigned int));
}
struct intel_partial_info {
u64 offset;
unsigned int size;
} __packed;
static inline void assert_intel_partial_info_is_packed(void)
{
BUILD_BUG_ON(sizeof(struct intel_partial_info) != sizeof(u64) + sizeof(unsigned int));
}
enum i915_ggtt_view_type {
I915_GGTT_VIEW_NORMAL = 0,
I915_GGTT_VIEW_ROTATED = sizeof(struct intel_rotation_info),
I915_GGTT_VIEW_PARTIAL = sizeof(struct intel_partial_info),
}; };
static inline void assert_i915_ggtt_view_type_is_unique(void)
{
/* As we encode the size of each branch inside the union into its type,
* we have to be careful that each branch has a unique size.
*/
switch ((enum i915_ggtt_view_type)0) {
case I915_GGTT_VIEW_NORMAL:
case I915_GGTT_VIEW_PARTIAL:
case I915_GGTT_VIEW_ROTATED:
/* gcc complains if these are identical cases */
break;
}
}
struct i915_ggtt_view { struct i915_ggtt_view {
enum i915_ggtt_view_type type; enum i915_ggtt_view_type type;
union { union {
struct { /* Members need to contain no holes/padding */
u64 offset; struct intel_partial_info partial;
unsigned int size;
} partial;
struct intel_rotation_info rotated; struct intel_rotation_info rotated;
} params; };
}; };
extern const struct i915_ggtt_view i915_ggtt_view_normal;
extern const struct i915_ggtt_view i915_ggtt_view_rotated;
enum i915_cache_level; enum i915_cache_level;
struct i915_vma; struct i915_vma;
...@@ -333,6 +359,7 @@ struct i915_ggtt { ...@@ -333,6 +359,7 @@ struct i915_ggtt {
/** "Graphics Stolen Memory" holds the global PTEs */ /** "Graphics Stolen Memory" holds the global PTEs */
void __iomem *gsm; void __iomem *gsm;
void (*invalidate)(struct drm_i915_private *dev_priv);
bool do_idle_maps; bool do_idle_maps;
...@@ -501,6 +528,8 @@ i915_vm_to_ggtt(struct i915_address_space *vm) ...@@ -501,6 +528,8 @@ i915_vm_to_ggtt(struct i915_address_space *vm)
int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv); int i915_ggtt_probe_hw(struct drm_i915_private *dev_priv);
int i915_ggtt_init_hw(struct drm_i915_private *dev_priv); int i915_ggtt_init_hw(struct drm_i915_private *dev_priv);
int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv); int i915_ggtt_enable_hw(struct drm_i915_private *dev_priv);
void i915_ggtt_enable_guc(struct drm_i915_private *i915);
void i915_ggtt_disable_guc(struct drm_i915_private *i915);
int i915_gem_init_ggtt(struct drm_i915_private *dev_priv); int i915_gem_init_ggtt(struct drm_i915_private *dev_priv);
void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv); void i915_ggtt_cleanup_hw(struct drm_i915_private *dev_priv);
...@@ -509,6 +538,7 @@ void i915_ppgtt_release(struct kref *kref); ...@@ -509,6 +538,7 @@ void i915_ppgtt_release(struct kref *kref);
struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv, struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_i915_private *dev_priv,
struct drm_i915_file_private *fpriv, struct drm_i915_file_private *fpriv,
const char *name); const char *name);
void i915_ppgtt_close(struct i915_address_space *vm);
static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt) static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
{ {
if (ppgtt) if (ppgtt)
...@@ -529,6 +559,16 @@ int __must_check i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, ...@@ -529,6 +559,16 @@ int __must_check i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj,
void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj, void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
struct sg_table *pages); struct sg_table *pages);
int i915_gem_gtt_reserve(struct i915_address_space *vm,
struct drm_mm_node *node,
u64 size, u64 offset, unsigned long color,
unsigned int flags);
int i915_gem_gtt_insert(struct i915_address_space *vm,
struct drm_mm_node *node,
u64 size, u64 alignment, unsigned long color,
u64 start, u64 end, unsigned int flags);
/* Flags used by pin/bind&friends. */ /* Flags used by pin/bind&friends. */
#define PIN_NONBLOCK BIT(0) #define PIN_NONBLOCK BIT(0)
#define PIN_MAPPABLE BIT(1) #define PIN_MAPPABLE BIT(1)
...@@ -543,6 +583,6 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj, ...@@ -543,6 +583,6 @@ void i915_gem_gtt_finish_pages(struct drm_i915_gem_object *obj,
#define PIN_HIGH BIT(9) #define PIN_HIGH BIT(9)
#define PIN_OFFSET_BIAS BIT(10) #define PIN_OFFSET_BIAS BIT(10)
#define PIN_OFFSET_FIXED BIT(11) #define PIN_OFFSET_FIXED BIT(11)
#define PIN_OFFSET_MASK (~4095) #define PIN_OFFSET_MASK (-I915_GTT_PAGE_SIZE)
#endif #endif
...@@ -151,10 +151,16 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = { ...@@ -151,10 +151,16 @@ static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = {
*/ */
struct drm_i915_gem_object * struct drm_i915_gem_object *
i915_gem_object_create_internal(struct drm_i915_private *i915, i915_gem_object_create_internal(struct drm_i915_private *i915,
unsigned int size) phys_addr_t size)
{ {
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
GEM_BUG_ON(!size);
GEM_BUG_ON(!IS_ALIGNED(size, PAGE_SIZE));
if (overflows_type(size, obj->base.size))
return ERR_PTR(-E2BIG);
obj = i915_gem_object_alloc(i915); obj = i915_gem_object_alloc(i915);
if (!obj) if (!obj)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -317,6 +317,29 @@ i915_gem_object_get_stride(struct drm_i915_gem_object *obj) ...@@ -317,6 +317,29 @@ i915_gem_object_get_stride(struct drm_i915_gem_object *obj)
return obj->tiling_and_stride & STRIDE_MASK; return obj->tiling_and_stride & STRIDE_MASK;
} }
static inline unsigned int
i915_gem_tile_height(unsigned int tiling)
{
GEM_BUG_ON(!tiling);
return tiling == I915_TILING_Y ? 32 : 8;
}
static inline unsigned int
i915_gem_object_get_tile_height(struct drm_i915_gem_object *obj)
{
return i915_gem_tile_height(i915_gem_object_get_tiling(obj));
}
static inline unsigned int
i915_gem_object_get_tile_row_size(struct drm_i915_gem_object *obj)
{
return (i915_gem_object_get_stride(obj) *
i915_gem_object_get_tile_height(obj));
}
int i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride);
static inline struct intel_engine_cs * static inline struct intel_engine_cs *
i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj) i915_gem_object_last_write_engine(struct drm_i915_gem_object *obj)
{ {
......
...@@ -187,20 +187,20 @@ int i915_gem_render_state_init(struct intel_engine_cs *engine) ...@@ -187,20 +187,20 @@ int i915_gem_render_state_init(struct intel_engine_cs *engine)
if (!rodata) if (!rodata)
return 0; return 0;
if (rodata->batch_items * 4 > 4096) if (rodata->batch_items * 4 > PAGE_SIZE)
return -EINVAL; return -EINVAL;
so = kmalloc(sizeof(*so), GFP_KERNEL); so = kmalloc(sizeof(*so), GFP_KERNEL);
if (!so) if (!so)
return -ENOMEM; return -ENOMEM;
obj = i915_gem_object_create_internal(engine->i915, 4096); obj = i915_gem_object_create_internal(engine->i915, PAGE_SIZE);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
ret = PTR_ERR(obj); ret = PTR_ERR(obj);
goto err_free; goto err_free;
} }
so->vma = i915_vma_create(obj, &engine->i915->ggtt.base, NULL); so->vma = i915_vma_instance(obj, &engine->i915->ggtt.base, NULL);
if (IS_ERR(so->vma)) { if (IS_ERR(so->vma)) {
ret = PTR_ERR(so->vma); ret = PTR_ERR(so->vma);
goto err_obj; goto err_obj;
......
...@@ -307,26 +307,6 @@ void i915_gem_request_retire_upto(struct drm_i915_gem_request *req) ...@@ -307,26 +307,6 @@ void i915_gem_request_retire_upto(struct drm_i915_gem_request *req)
} while (tmp != req); } while (tmp != req);
} }
static int i915_gem_check_wedge(struct drm_i915_private *dev_priv)
{
struct i915_gpu_error *error = &dev_priv->gpu_error;
if (i915_terminally_wedged(error))
return -EIO;
if (i915_reset_in_progress(error)) {
/* Non-interruptible callers can't handle -EAGAIN, hence return
* -EIO unconditionally for these.
*/
if (!dev_priv->mm.interruptible)
return -EIO;
return -EAGAIN;
}
return 0;
}
static int i915_gem_init_global_seqno(struct drm_i915_private *i915, u32 seqno) static int i915_gem_init_global_seqno(struct drm_i915_private *i915, u32 seqno)
{ {
struct i915_gem_timeline *timeline = &i915->gt.global_timeline; struct i915_gem_timeline *timeline = &i915->gt.global_timeline;
...@@ -521,12 +501,10 @@ i915_gem_request_alloc(struct intel_engine_cs *engine, ...@@ -521,12 +501,10 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
lockdep_assert_held(&dev_priv->drm.struct_mutex); lockdep_assert_held(&dev_priv->drm.struct_mutex);
/* ABI: Before userspace accesses the GPU (e.g. execbuffer), report /* ABI: Before userspace accesses the GPU (e.g. execbuffer), report
* EIO if the GPU is already wedged, or EAGAIN to drop the struct_mutex * EIO if the GPU is already wedged.
* and restart.
*/ */
ret = i915_gem_check_wedge(dev_priv); if (i915_terminally_wedged(&dev_priv->gpu_error))
if (ret) return ERR_PTR(-EIO);
return ERR_PTR(ret);
/* Pinning the contexts may generate requests in order to acquire /* Pinning the contexts may generate requests in order to acquire
* GGTT space, so do this first before we reserve a seqno for * GGTT space, so do this first before we reserve a seqno for
...@@ -851,6 +829,13 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches) ...@@ -851,6 +829,13 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
lockdep_assert_held(&request->i915->drm.struct_mutex); lockdep_assert_held(&request->i915->drm.struct_mutex);
trace_i915_gem_request_add(request); trace_i915_gem_request_add(request);
/* Make sure that no request gazumped us - if it was allocated after
* our i915_gem_request_alloc() and called __i915_add_request() before
* us, the timeline will hold its seqno which is later than ours.
*/
GEM_BUG_ON(i915_seqno_passed(timeline->last_submitted_seqno,
request->fence.seqno));
/* /*
* To ensure that this call will not fail, space for its emissions * To ensure that this call will not fail, space for its emissions
* should already have been reserved in the ring buffer. Let the ring * should already have been reserved in the ring buffer. Let the ring
......
...@@ -647,8 +647,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ...@@ -647,8 +647,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
stolen_offset, gtt_offset, size); stolen_offset, gtt_offset, size);
/* KISS and expect everything to be page-aligned */ /* KISS and expect everything to be page-aligned */
if (WARN_ON(size == 0) || WARN_ON(size & 4095) || if (WARN_ON(size == 0) ||
WARN_ON(stolen_offset & 4095)) WARN_ON(!IS_ALIGNED(size, I915_GTT_PAGE_SIZE)) ||
WARN_ON(!IS_ALIGNED(stolen_offset, I915_GTT_MIN_ALIGNMENT)))
return NULL; return NULL;
stolen = kzalloc(sizeof(*stolen), GFP_KERNEL); stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
...@@ -682,7 +683,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ...@@ -682,7 +683,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
if (ret) if (ret)
goto err; goto err;
vma = i915_gem_obj_lookup_or_create_vma(obj, &ggtt->base, NULL); vma = i915_vma_instance(obj, &ggtt->base, NULL);
if (IS_ERR(vma)) { if (IS_ERR(vma)) {
ret = PTR_ERR(vma); ret = PTR_ERR(vma);
goto err_pages; goto err_pages;
...@@ -693,15 +694,16 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv ...@@ -693,15 +694,16 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
* setting up the GTT space. The actual reservation will occur * setting up the GTT space. The actual reservation will occur
* later. * later.
*/ */
vma->node.start = gtt_offset; ret = i915_gem_gtt_reserve(&ggtt->base, &vma->node,
vma->node.size = size; size, gtt_offset, obj->cache_level,
0);
ret = drm_mm_reserve_node(&ggtt->base.mm, &vma->node);
if (ret) { if (ret) {
DRM_DEBUG_KMS("failed to allocate stolen GTT space\n"); DRM_DEBUG_KMS("failed to allocate stolen GTT space\n");
goto err_pages; goto err_pages;
} }
GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
vma->pages = obj->mm.pages; vma->pages = obj->mm.pages;
vma->flags |= I915_VMA_GLOBAL_BIND; vma->flags |= I915_VMA_GLOBAL_BIND;
__i915_vma_set_map_and_fenceable(vma); __i915_vma_set_map_and_fenceable(vma);
......
...@@ -34,8 +34,8 @@ ...@@ -34,8 +34,8 @@
/** /**
* DOC: buffer object tiling * DOC: buffer object tiling
* *
* i915_gem_set_tiling() and i915_gem_get_tiling() is the userspace interface to * i915_gem_set_tiling_ioctl() and i915_gem_get_tiling_ioctl() is the userspace
* declare fence register requirements. * interface to declare fence register requirements.
* *
* In principle GEM doesn't care at all about the internal data layout of an * In principle GEM doesn't care at all about the internal data layout of an
* object, and hence it also doesn't care about tiling or swizzling. There's two * object, and hence it also doesn't care about tiling or swizzling. There's two
...@@ -58,86 +58,147 @@ ...@@ -58,86 +58,147 @@
* invovlement. * invovlement.
*/ */
/**
* i915_gem_fence_size - required global GTT size for a fence
* @i915: i915 device
* @size: object size
* @tiling: tiling mode
* @stride: tiling stride
*
* Return the required global GTT size for a fence (view of a tiled object),
* taking into account potential fence register mapping.
*/
u32 i915_gem_fence_size(struct drm_i915_private *i915,
u32 size, unsigned int tiling, unsigned int stride)
{
u32 ggtt_size;
GEM_BUG_ON(!size);
if (tiling == I915_TILING_NONE)
return size;
GEM_BUG_ON(!stride);
if (INTEL_GEN(i915) >= 4) {
stride *= i915_gem_tile_height(tiling);
GEM_BUG_ON(!IS_ALIGNED(stride, I965_FENCE_PAGE));
return roundup(size, stride);
}
/* Previous chips need a power-of-two fence region when tiling */
if (IS_GEN3(i915))
ggtt_size = 1024*1024;
else
ggtt_size = 512*1024;
while (ggtt_size < size)
ggtt_size <<= 1;
return ggtt_size;
}
/**
* i915_gem_fence_alignment - required global GTT alignment for a fence
* @i915: i915 device
* @size: object size
* @tiling: tiling mode
* @stride: tiling stride
*
* Return the required global GTT alignment for a fence (a view of a tiled
* object), taking into account potential fence register mapping.
*/
u32 i915_gem_fence_alignment(struct drm_i915_private *i915, u32 size,
unsigned int tiling, unsigned int stride)
{
GEM_BUG_ON(!size);
/*
* Minimum alignment is 4k (GTT page size), but might be greater
* if a fence register is needed for the object.
*/
if (tiling == I915_TILING_NONE)
return I915_GTT_MIN_ALIGNMENT;
if (INTEL_GEN(i915) >= 4)
return I965_FENCE_PAGE;
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object.
*/
return i915_gem_fence_size(i915, size, tiling, stride);
}
/* Check pitch constriants for all chips & tiling formats */ /* Check pitch constriants for all chips & tiling formats */
static bool static bool
i915_tiling_ok(struct drm_i915_private *dev_priv, i915_tiling_ok(struct drm_i915_gem_object *obj,
int stride, int size, int tiling_mode) unsigned int tiling, unsigned int stride)
{ {
int tile_width; struct drm_i915_private *i915 = to_i915(obj->base.dev);
unsigned int tile_width;
/* Linear is always fine */ /* Linear is always fine */
if (tiling_mode == I915_TILING_NONE) if (tiling == I915_TILING_NONE)
return true; return true;
if (tiling_mode > I915_TILING_LAST) if (tiling > I915_TILING_LAST)
return false; return false;
if (IS_GEN2(dev_priv) ||
(tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev_priv)))
tile_width = 128;
else
tile_width = 512;
/* check maximum stride & object size */ /* check maximum stride & object size */
/* i965+ stores the end address of the gtt mapping in the fence /* i965+ stores the end address of the gtt mapping in the fence
* reg, so dont bother to check the size */ * reg, so dont bother to check the size */
if (INTEL_GEN(dev_priv) >= 7) { if (INTEL_GEN(i915) >= 7) {
if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL) if (stride / 128 > GEN7_FENCE_MAX_PITCH_VAL)
return false; return false;
} else if (INTEL_GEN(dev_priv) >= 4) { } else if (INTEL_GEN(i915) >= 4) {
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return false; return false;
} else { } else {
if (stride > 8192) if (stride > 8192)
return false; return false;
if (IS_GEN3(dev_priv)) { if (IS_GEN3(i915)) {
if (size > I830_FENCE_MAX_SIZE_VAL << 20) if (obj->base.size > I830_FENCE_MAX_SIZE_VAL << 20)
return false; return false;
} else { } else {
if (size > I830_FENCE_MAX_SIZE_VAL << 19) if (obj->base.size > I830_FENCE_MAX_SIZE_VAL << 19)
return false; return false;
} }
} }
if (stride < tile_width) if (IS_GEN2(i915) ||
(tiling == I915_TILING_Y && HAS_128_BYTE_Y_TILING(i915)))
tile_width = 128;
else
tile_width = 512;
if (!IS_ALIGNED(stride, tile_width))
return false; return false;
/* 965+ just needs multiples of tile width */ /* 965+ just needs multiples of tile width */
if (INTEL_GEN(dev_priv) >= 4) { if (INTEL_GEN(i915) >= 4)
if (stride & (tile_width - 1))
return false;
return true; return true;
}
/* Pre-965 needs power of two tile widths */ /* Pre-965 needs power of two tile widths */
if (stride & (stride - 1)) return is_power_of_2(stride);
return false;
return true;
} }
static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode) static bool i915_vma_fence_prepare(struct i915_vma *vma,
int tiling_mode, unsigned int stride)
{ {
struct drm_i915_private *dev_priv = vma->vm->i915; struct drm_i915_private *i915 = vma->vm->i915;
u32 size; u32 size, alignment;
if (!i915_vma_is_map_and_fenceable(vma)) if (!i915_vma_is_map_and_fenceable(vma))
return true; return true;
if (INTEL_GEN(dev_priv) == 3) { size = i915_gem_fence_size(i915, vma->size, tiling_mode, stride);
if (vma->node.start & ~I915_FENCE_START_MASK)
return false;
} else {
if (vma->node.start & ~I830_FENCE_START_MASK)
return false;
}
size = i915_gem_get_ggtt_size(dev_priv, vma->size, tiling_mode);
if (vma->node.size < size) if (vma->node.size < size)
return false; return false;
if (vma->node.start & (size - 1)) alignment = i915_gem_fence_alignment(i915, vma->size, tiling_mode, stride);
if (!IS_ALIGNED(vma->node.start, alignment))
return false; return false;
return true; return true;
...@@ -145,20 +206,20 @@ static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode) ...@@ -145,20 +206,20 @@ static bool i915_vma_fence_prepare(struct i915_vma *vma, int tiling_mode)
/* Make the current GTT allocation valid for the change in tiling. */ /* Make the current GTT allocation valid for the change in tiling. */
static int static int
i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode) i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj,
int tiling_mode, unsigned int stride)
{ {
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
struct i915_vma *vma; struct i915_vma *vma;
int ret; int ret;
if (tiling_mode == I915_TILING_NONE) if (tiling_mode == I915_TILING_NONE)
return 0; return 0;
if (INTEL_GEN(dev_priv) >= 4)
return 0;
list_for_each_entry(vma, &obj->vma_list, obj_link) { list_for_each_entry(vma, &obj->vma_list, obj_link) {
if (i915_vma_fence_prepare(vma, tiling_mode)) if (!i915_vma_is_ggtt(vma))
break;
if (i915_vma_fence_prepare(vma, tiling_mode, stride))
continue; continue;
ret = i915_vma_unbind(vma); ret = i915_vma_unbind(vma);
...@@ -169,8 +230,100 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode) ...@@ -169,8 +230,100 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode)
return 0; return 0;
} }
int
i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
unsigned int tiling, unsigned int stride)
{
struct drm_i915_private *i915 = to_i915(obj->base.dev);
struct i915_vma *vma;
int err;
/* Make sure we don't cross-contaminate obj->tiling_and_stride */
BUILD_BUG_ON(I915_TILING_LAST & STRIDE_MASK);
GEM_BUG_ON(!i915_tiling_ok(obj, tiling, stride));
GEM_BUG_ON(!stride ^ (tiling == I915_TILING_NONE));
lockdep_assert_held(&i915->drm.struct_mutex);
if ((tiling | stride) == obj->tiling_and_stride)
return 0;
if (obj->framebuffer_references)
return -EBUSY;
/* We need to rebind the object if its current allocation
* no longer meets the alignment restrictions for its new
* tiling mode. Otherwise we can just leave it alone, but
* need to ensure that any fence register is updated before
* the next fenced (either through the GTT or by the BLT unit
* on older GPUs) access.
*
* After updating the tiling parameters, we then flag whether
* we need to update an associated fence register. Note this
* has to also include the unfenced register the GPU uses
* whilst executing a fenced command for an untiled object.
*/
err = i915_gem_object_fence_prepare(obj, tiling, stride);
if (err)
return err;
/* If the memory has unknown (i.e. varying) swizzling, we pin the
* pages to prevent them being swapped out and causing corruption
* due to the change in swizzling.
*/
mutex_lock(&obj->mm.lock);
if (obj->mm.pages &&
obj->mm.madv == I915_MADV_WILLNEED &&
i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
if (tiling == I915_TILING_NONE) {
GEM_BUG_ON(!obj->mm.quirked);
__i915_gem_object_unpin_pages(obj);
obj->mm.quirked = false;
}
if (!i915_gem_object_is_tiled(obj)) {
GEM_BUG_ON(!obj->mm.quirked);
__i915_gem_object_pin_pages(obj);
obj->mm.quirked = true;
}
}
mutex_unlock(&obj->mm.lock);
list_for_each_entry(vma, &obj->vma_list, obj_link) {
if (!i915_vma_is_ggtt(vma))
break;
vma->fence_size =
i915_gem_fence_size(i915, vma->size, tiling, stride);
vma->fence_alignment =
i915_gem_fence_alignment(i915,
vma->size, tiling, stride);
if (vma->fence)
vma->fence->dirty = true;
}
obj->tiling_and_stride = tiling | stride;
/* Force the fence to be reacquired for GTT access */
i915_gem_release_mmap(obj);
/* Try to preallocate memory required to save swizzling on put-pages */
if (i915_gem_object_needs_bit17_swizzle(obj)) {
if (!obj->bit_17) {
obj->bit_17 = kcalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT),
sizeof(long), GFP_KERNEL);
}
} else {
kfree(obj->bit_17);
obj->bit_17 = NULL;
}
return 0;
}
/** /**
* i915_gem_set_tiling - IOCTL handler to set tiling mode * i915_gem_set_tiling_ioctl - IOCTL handler to set tiling mode
* @dev: DRM device * @dev: DRM device
* @data: data pointer for the ioctl * @data: data pointer for the ioctl
* @file: DRM file for the ioctl call * @file: DRM file for the ioctl call
...@@ -184,30 +337,19 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode) ...@@ -184,30 +337,19 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj, int tiling_mode)
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
int int
i915_gem_set_tiling(struct drm_device *dev, void *data, i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
struct drm_file *file) struct drm_file *file)
{ {
struct drm_i915_gem_set_tiling *args = data; struct drm_i915_gem_set_tiling *args = data;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
int err = 0; int err;
/* Make sure we don't cross-contaminate obj->tiling_and_stride */
BUILD_BUG_ON(I915_TILING_LAST & STRIDE_MASK);
obj = i915_gem_object_lookup(file, args->handle); obj = i915_gem_object_lookup(file, args->handle);
if (!obj) if (!obj)
return -ENOENT; return -ENOENT;
if (!i915_tiling_ok(dev_priv, if (!i915_tiling_ok(obj, args->tiling_mode, args->stride)) {
args->stride, obj->base.size, args->tiling_mode)) { err = -EINVAL;
i915_gem_object_put(obj);
return -EINVAL;
}
mutex_lock(&dev->struct_mutex);
if (obj->pin_display || obj->framebuffer_references) {
err = -EBUSY;
goto err; goto err;
} }
...@@ -216,9 +358,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -216,9 +358,9 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
args->stride = 0; args->stride = 0;
} else { } else {
if (args->tiling_mode == I915_TILING_X) if (args->tiling_mode == I915_TILING_X)
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; args->swizzle_mode = to_i915(dev)->mm.bit_6_swizzle_x;
else else
args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; args->swizzle_mode = to_i915(dev)->mm.bit_6_swizzle_y;
/* Hide bit 17 swizzling from the user. This prevents old Mesa /* Hide bit 17 swizzling from the user. This prevents old Mesa
* from aborting the application on sw fallbacks to bit 17, * from aborting the application on sw fallbacks to bit 17,
...@@ -240,79 +382,24 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -240,79 +382,24 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
} }
} }
if (args->tiling_mode != i915_gem_object_get_tiling(obj) || err = mutex_lock_interruptible(&dev->struct_mutex);
args->stride != i915_gem_object_get_stride(obj)) { if (err)
/* We need to rebind the object if its current allocation goto err;
* no longer meets the alignment restrictions for its new
* tiling mode. Otherwise we can just leave it alone, but
* need to ensure that any fence register is updated before
* the next fenced (either through the GTT or by the BLT unit
* on older GPUs) access.
*
* After updating the tiling parameters, we then flag whether
* we need to update an associated fence register. Note this
* has to also include the unfenced register the GPU uses
* whilst executing a fenced command for an untiled object.
*/
err = i915_gem_object_fence_prepare(obj, args->tiling_mode);
if (!err) {
struct i915_vma *vma;
mutex_lock(&obj->mm.lock);
if (obj->mm.pages &&
obj->mm.madv == I915_MADV_WILLNEED &&
dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) {
if (args->tiling_mode == I915_TILING_NONE) {
GEM_BUG_ON(!obj->mm.quirked);
__i915_gem_object_unpin_pages(obj);
obj->mm.quirked = false;
}
if (!i915_gem_object_is_tiled(obj)) {
GEM_BUG_ON(!obj->mm.quirked);
__i915_gem_object_pin_pages(obj);
obj->mm.quirked = true;
}
}
mutex_unlock(&obj->mm.lock);
list_for_each_entry(vma, &obj->vma_list, obj_link) {
if (!vma->fence)
continue;
vma->fence->dirty = true; err = i915_gem_object_set_tiling(obj, args->tiling_mode, args->stride);
} mutex_unlock(&dev->struct_mutex);
obj->tiling_and_stride =
args->stride | args->tiling_mode;
/* Force the fence to be reacquired for GTT access */ /* We have to maintain this existing ABI... */
i915_gem_release_mmap(obj);
}
}
/* we have to maintain this existing ABI... */
args->stride = i915_gem_object_get_stride(obj); args->stride = i915_gem_object_get_stride(obj);
args->tiling_mode = i915_gem_object_get_tiling(obj); args->tiling_mode = i915_gem_object_get_tiling(obj);
/* Try to preallocate memory required to save swizzling on put-pages */
if (i915_gem_object_needs_bit17_swizzle(obj)) {
if (obj->bit_17 == NULL) {
obj->bit_17 = kcalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT),
sizeof(long), GFP_KERNEL);
}
} else {
kfree(obj->bit_17);
obj->bit_17 = NULL;
}
err: err:
i915_gem_object_put(obj); i915_gem_object_put(obj);
mutex_unlock(&dev->struct_mutex);
return err; return err;
} }
/** /**
* i915_gem_get_tiling - IOCTL handler to get tiling mode * i915_gem_get_tiling_ioctl - IOCTL handler to get tiling mode
* @dev: DRM device * @dev: DRM device
* @data: data pointer for the ioctl * @data: data pointer for the ioctl
* @file: DRM file for the ioctl call * @file: DRM file for the ioctl call
...@@ -325,7 +412,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -325,7 +412,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
* Zero on success, negative errno on failure. * Zero on success, negative errno on failure.
*/ */
int int
i915_gem_get_tiling(struct drm_device *dev, void *data, i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
struct drm_file *file) struct drm_file *file)
{ {
struct drm_i915_gem_get_tiling *args = data; struct drm_i915_gem_get_tiling *args = data;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment