提交 3e09dcd5 编写于 作者: D Dave Airlie

Merge tag 'drm-intel-next-2014-02-07' of ssh://git.freedesktop.org/git/drm-intel into drm-next

- Yet more steps towards atomic modeset from Ville.
- DP panel power sequencing improvements from Paulo.
- irq code cleanups from Ville.
- 5.4 GHz dp lane clock support for bdw/hsw from Todd.
- Clock readout support for hsw/bdw (aka fastboot) from Jesse.
- Make pipe underruns report at ERROR level (Ville). This is to check our
  improved watermarks code.
- Full ppgtt support from Ben for gen7.
- More fbc fixes and improvements from Ville all over the place, unfortunately
  not yet enabled by default on more platforms.
- w/a cleanups from Ville.
- HiZ stall optimization settings (Chia-I Wu).
- Display register mmio offset refactor patch from Antti.
- RPS improvements for corner-cases from Jeff McGee.

* tag 'drm-intel-next-2014-02-07' of ssh://git.freedesktop.org/git/drm-intel: (166 commits)
  drm/i915: Update rps interrupt limits
  drm/i915: Restore rps/rc6 on reset
  drm/i915: Prevent recursion by retiring requests when the ring is full
  drm/i915: Generate a hang error code
  drm/i915: unify FLIP_DONE macro names
  drm/i915: vlv: s/spin_lock_irqsave/spin_lock/ in irq handler
  drm/i915: factor out valleyview_pipestat_irq_handler
  drm/i915: vlv: don't unmask IIR[DISPLAY_PIPE_A/B_VBLANK] interrupt
  drm/i915: Reorganize display pipe register accesses
  drm/i915: Treat using a purged buffer as a source of EFAULT
  drm/i915: Convert EFAULT into a silent SIGBUS
  drm/i915: release mutex in i915_gem_init()'s error path
  drm/i915: check for oom when allocating private_default_ctx
  drm/i915/vlv: WA to fix Voltage not getting dropped to Vmin when Gfx is power gated.
  drm/i915: Get rid of acthd based guilty batch search
  drm/i915: Use hangcheck score to find guilty context
  drm/i915: Drop WaDisablePSDDualDispatchEnable:ivb for IVB GT2
  drm/i915: Fix IVB GT2 WaDisableDopClockGating and WaDisablePSDDualDispatchEnable
  drm/i915: Don't access snooped pages through the GTT (even for error capture)
  drm/i915: Only print information for filing bug reports once
  ...

Conflicts:
	drivers/gpu/drm/i915/intel_dp.c
......@@ -14,6 +14,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
i915_gem_gtt.o \
i915_gem_stolen.o \
i915_gem_tiling.o \
i915_params.o \
i915_sysfs.o \
i915_trace_points.o \
i915_ums.o \
......
......@@ -98,7 +98,7 @@ static const char *get_pin_flag(struct drm_i915_gem_object *obj)
{
if (obj->user_pin_count > 0)
return "P";
else if (obj->pin_count > 0)
else if (i915_gem_obj_is_pinned(obj))
return "p";
else
return " ";
......@@ -123,6 +123,8 @@ static void
describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
{
struct i915_vma *vma;
int pin_count = 0;
seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s",
&obj->base,
get_pin_flag(obj),
......@@ -139,8 +141,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
if (obj->base.name)
seq_printf(m, " (name: %d)", obj->base.name);
if (obj->pin_count)
seq_printf(m, " (pinned x %d)", obj->pin_count);
list_for_each_entry(vma, &obj->vma_list, vma_link)
if (vma->pin_count > 0)
pin_count++;
seq_printf(m, " (pinned x %d)", pin_count);
if (obj->pin_display)
seq_printf(m, " (display)");
if (obj->fence_reg != I915_FENCE_REG_NONE)
......@@ -447,7 +451,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
total_obj_size = total_gtt_size = count = 0;
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
if (list == PINNED_LIST && obj->pin_count == 0)
if (list == PINNED_LIST && !i915_gem_obj_is_pinned(obj))
continue;
seq_puts(m, " ");
......@@ -712,8 +716,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
seq_printf(m, "Graphics Interrupt mask: %08x\n",
I915_READ(GTIMR));
}
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
for_each_ring(ring, dev_priv, i) {
if (INTEL_INFO(dev)->gen >= 6) {
seq_printf(m,
......@@ -1733,6 +1735,17 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
return 0;
}
static int per_file_ctx(int id, void *ptr, void *data)
{
struct i915_hw_context *ctx = ptr;
struct seq_file *m = data;
struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx);
ppgtt->debug_dump(ppgtt, m);
return 0;
}
static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
......@@ -1762,6 +1775,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
struct drm_file *file;
int i;
if (INTEL_INFO(dev)->gen == 6)
......@@ -1780,6 +1794,20 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
seq_puts(m, "aliasing PPGTT:\n");
seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
ppgtt->debug_dump(ppgtt, m);
} else
return;
list_for_each_entry_reverse(file, &dev->filelist, lhead) {
struct drm_i915_file_private *file_priv = file->driver_priv;
struct i915_hw_ppgtt *pvt_ppgtt;
pvt_ppgtt = ctx_to_ppgtt(file_priv->private_default_ctx);
seq_printf(m, "proc: %s\n",
get_pid_task(file->pid, PIDTYPE_PID)->comm);
seq_puts(m, " default context:\n");
idr_for_each(&file_priv->context_idr, per_file_ctx, m);
}
seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
}
......@@ -1892,6 +1920,44 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
return 0;
}
static int i915_sink_crc(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct intel_encoder *encoder;
struct intel_connector *connector;
struct intel_dp *intel_dp = NULL;
int ret;
u8 crc[6];
drm_modeset_lock_all(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list,
base.head) {
if (connector->base.dpms != DRM_MODE_DPMS_ON)
continue;
encoder = to_intel_encoder(connector->base.encoder);
if (encoder->type != INTEL_OUTPUT_EDP)
continue;
intel_dp = enc_to_intel_dp(&encoder->base);
ret = intel_dp_sink_crc(intel_dp, crc);
if (ret)
goto out;
seq_printf(m, "%02x%02x%02x%02x%02x%02x\n",
crc[0], crc[1], crc[2],
crc[3], crc[4], crc[5]);
goto out;
}
ret = -ENODEV;
out:
drm_modeset_unlock_all(dev);
return ret;
}
static int i915_energy_uJ(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
......@@ -2756,6 +2822,174 @@ static const struct file_operations i915_display_crc_ctl_fops = {
.write = display_crc_ctl_write
};
static void wm_latency_show(struct seq_file *m, const uint16_t wm[5])
{
struct drm_device *dev = m->private;
int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
int level;
drm_modeset_lock_all(dev);
for (level = 0; level < num_levels; level++) {
unsigned int latency = wm[level];
/* WM1+ latency values in 0.5us units */
if (level > 0)
latency *= 5;
seq_printf(m, "WM%d %u (%u.%u usec)\n",
level, wm[level],
latency / 10, latency % 10);
}
drm_modeset_unlock_all(dev);
}
static int pri_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_device *dev = m->private;
wm_latency_show(m, to_i915(dev)->wm.pri_latency);
return 0;
}
static int spr_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_device *dev = m->private;
wm_latency_show(m, to_i915(dev)->wm.spr_latency);
return 0;
}
static int cur_wm_latency_show(struct seq_file *m, void *data)
{
struct drm_device *dev = m->private;
wm_latency_show(m, to_i915(dev)->wm.cur_latency);
return 0;
}
static int pri_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
if (!HAS_PCH_SPLIT(dev))
return -ENODEV;
return single_open(file, pri_wm_latency_show, dev);
}
static int spr_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
if (!HAS_PCH_SPLIT(dev))
return -ENODEV;
return single_open(file, spr_wm_latency_show, dev);
}
static int cur_wm_latency_open(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
if (!HAS_PCH_SPLIT(dev))
return -ENODEV;
return single_open(file, cur_wm_latency_show, dev);
}
static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp, uint16_t wm[5])
{
struct seq_file *m = file->private_data;
struct drm_device *dev = m->private;
uint16_t new[5] = { 0 };
int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
int level;
int ret;
char tmp[32];
if (len >= sizeof(tmp))
return -EINVAL;
if (copy_from_user(tmp, ubuf, len))
return -EFAULT;
tmp[len] = '\0';
ret = sscanf(tmp, "%hu %hu %hu %hu %hu", &new[0], &new[1], &new[2], &new[3], &new[4]);
if (ret != num_levels)
return -EINVAL;
drm_modeset_lock_all(dev);
for (level = 0; level < num_levels; level++)
wm[level] = new[level];
drm_modeset_unlock_all(dev);
return len;
}
static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_device *dev = m->private;
return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency);
}
static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_device *dev = m->private;
return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency);
}
static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct seq_file *m = file->private_data;
struct drm_device *dev = m->private;
return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency);
}
static const struct file_operations i915_pri_wm_latency_fops = {
.owner = THIS_MODULE,
.open = pri_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = pri_wm_latency_write
};
static const struct file_operations i915_spr_wm_latency_fops = {
.owner = THIS_MODULE,
.open = spr_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = spr_wm_latency_write
};
static const struct file_operations i915_cur_wm_latency_fops = {
.owner = THIS_MODULE,
.open = cur_wm_latency_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = cur_wm_latency_write
};
static int
i915_wedged_get(void *data, u64 *val)
{
......@@ -2929,7 +3163,7 @@ i915_drop_caches_set(void *data, u64 val)
list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
list_for_each_entry_safe(vma, x, &vm->inactive_list,
mm_list) {
if (vma->obj->pin_count)
if (vma->pin_count)
continue;
ret = i915_vma_unbind(vma);
......@@ -2989,6 +3223,7 @@ i915_max_freq_set(void *data, u64 val)
{
struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 rp_state_cap, hw_max, hw_min;
int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
......@@ -3007,14 +3242,29 @@ i915_max_freq_set(void *data, u64 val)
*/
if (IS_VALLEYVIEW(dev)) {
val = vlv_freq_opcode(dev_priv, val);
dev_priv->rps.max_delay = val;
valleyview_set_rps(dev, val);
hw_max = valleyview_rps_max_freq(dev_priv);
hw_min = valleyview_rps_min_freq(dev_priv);
} else {
do_div(val, GT_FREQUENCY_MULTIPLIER);
dev_priv->rps.max_delay = val;
gen6_set_rps(dev, val);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.hw_max;
hw_min = (rp_state_cap >> 16) & 0xff;
}
if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL;
}
dev_priv->rps.max_delay = val;
if (IS_VALLEYVIEW(dev))
valleyview_set_rps(dev, val);
else
gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
......@@ -3054,6 +3304,7 @@ i915_min_freq_set(void *data, u64 val)
{
struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 rp_state_cap, hw_max, hw_min;
int ret;
if (!(IS_GEN6(dev) || IS_GEN7(dev)))
......@@ -3072,13 +3323,29 @@ i915_min_freq_set(void *data, u64 val)
*/
if (IS_VALLEYVIEW(dev)) {
val = vlv_freq_opcode(dev_priv, val);
dev_priv->rps.min_delay = val;
valleyview_set_rps(dev, val);
hw_max = valleyview_rps_max_freq(dev_priv);
hw_min = valleyview_rps_min_freq(dev_priv);
} else {
do_div(val, GT_FREQUENCY_MULTIPLIER);
dev_priv->rps.min_delay = val;
gen6_set_rps(dev, val);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.hw_max;
hw_min = (rp_state_cap >> 16) & 0xff;
}
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL;
}
dev_priv->rps.min_delay = val;
if (IS_VALLEYVIEW(dev))
valleyview_set_rps(dev, val);
else
gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
......@@ -3248,6 +3515,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_dpio", i915_dpio_info, 0},
{"i915_llc", i915_llc, 0},
{"i915_edp_psr_status", i915_edp_psr_status, 0},
{"i915_sink_crc_eDP1", i915_sink_crc, 0},
{"i915_energy_uJ", i915_energy_uJ, 0},
{"i915_pc8_status", i915_pc8_status, 0},
{"i915_power_domain_info", i915_power_domain_info, 0},
......@@ -3269,6 +3537,9 @@ static const struct i915_debugfs_files {
{"i915_error_state", &i915_error_state_fops},
{"i915_next_seqno", &i915_next_seqno_fops},
{"i915_display_crc_ctl", &i915_display_crc_ctl_fops},
{"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
{"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
{"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
};
void intel_display_crc_init(struct drm_device *dev)
......
......@@ -990,7 +990,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = HAS_WT(dev);
break;
case I915_PARAM_HAS_ALIASING_PPGTT:
value = dev_priv->mm.aliasing_ppgtt ? 1 : 0;
value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev);
break;
case I915_PARAM_HAS_WAIT_TIMEOUT:
value = 1;
......@@ -1374,7 +1374,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
WARN_ON(dev_priv->mm.aliasing_ppgtt);
drm_mm_takedown(&dev_priv->gtt.base.mm);
cleanup_power:
intel_display_power_put(dev, POWER_DOMAIN_VGA);
......@@ -1776,8 +1776,8 @@ int i915_driver_unload(struct drm_device *dev)
i915_gem_free_all_phys_object(dev);
i915_gem_cleanup_ringbuffer(dev);
i915_gem_context_fini(dev);
WARN_ON(dev_priv->mm.aliasing_ppgtt);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
i915_gem_cleanup_stolen(dev);
if (!I915_NEED_GFX_HWS(dev))
......
......@@ -38,134 +38,30 @@
#include <linux/module.h>
#include <drm/drm_crtc_helper.h>
static int i915_modeset __read_mostly = -1;
module_param_named(modeset, i915_modeset, int, 0400);
MODULE_PARM_DESC(modeset,
"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
"1=on, -1=force vga console preference [default])");
unsigned int i915_fbpercrtc __always_unused = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
int i915_panel_ignore_lid __read_mostly = 1;
module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600);
MODULE_PARM_DESC(panel_ignore_lid,
"Override lid status (0=autodetect, 1=autodetect disabled [default], "
"-1=force lid closed, -2=force lid open)");
unsigned int i915_powersave __read_mostly = 1;
module_param_named(powersave, i915_powersave, int, 0600);
MODULE_PARM_DESC(powersave,
"Enable powersavings, fbc, downclocking, etc. (default: true)");
int i915_semaphores __read_mostly = -1;
module_param_named(semaphores, i915_semaphores, int, 0400);
MODULE_PARM_DESC(semaphores,
"Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))");
int i915_enable_rc6 __read_mostly = -1;
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400);
MODULE_PARM_DESC(i915_enable_rc6,
"Enable power-saving render C-state 6. "
"Different stages can be selected via bitmask values "
"(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
"default: -1 (use per-chip default)");
int i915_enable_fbc __read_mostly = -1;
module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
MODULE_PARM_DESC(i915_enable_fbc,
"Enable frame buffer compression for power savings "
"(default: -1 (use per-chip default))");
unsigned int i915_lvds_downclock __read_mostly = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
MODULE_PARM_DESC(lvds_downclock,
"Use panel (LVDS/eDP) downclocking for power savings "
"(default: false)");
int i915_lvds_channel_mode __read_mostly;
module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600);
MODULE_PARM_DESC(lvds_channel_mode,
"Specify LVDS channel mode "
"(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
int i915_panel_use_ssc __read_mostly = -1;
module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc,
"Use Spread Spectrum Clock with panels [LVDS/eDP] "
"(default: auto from VBT)");
int i915_vbt_sdvo_panel_type __read_mostly = -1;
module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
MODULE_PARM_DESC(vbt_sdvo_panel_type,
"Override/Ignore selection of SDVO panel mode in the VBT "
"(-2=ignore, -1=auto [default], index in VBT BIOS table)");
static bool i915_try_reset __read_mostly = true;
module_param_named(reset, i915_try_reset, bool, 0600);
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
bool i915_enable_hangcheck __read_mostly = true;
module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644);
MODULE_PARM_DESC(enable_hangcheck,
"Periodically check GPU activity for detecting hangs. "
"WARNING: Disabling this can cause system wide hangs. "
"(default: true)");
int i915_enable_ppgtt __read_mostly = -1;
module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400);
MODULE_PARM_DESC(i915_enable_ppgtt,
"Enable PPGTT (default: true)");
int i915_enable_psr __read_mostly = 0;
module_param_named(enable_psr, i915_enable_psr, int, 0600);
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
unsigned int i915_preliminary_hw_support __read_mostly = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT);
module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
MODULE_PARM_DESC(preliminary_hw_support,
"Enable preliminary hardware support.");
int i915_disable_power_well __read_mostly = 1;
module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
MODULE_PARM_DESC(disable_power_well,
"Disable the power well when possible (default: true)");
int i915_enable_ips __read_mostly = 1;
module_param_named(enable_ips, i915_enable_ips, int, 0600);
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
bool i915_fastboot __read_mostly = 0;
module_param_named(fastboot, i915_fastboot, bool, 0600);
MODULE_PARM_DESC(fastboot, "Try to skip unnecessary mode sets at boot time "
"(default: false)");
int i915_enable_pc8 __read_mostly = 1;
module_param_named(enable_pc8, i915_enable_pc8, int, 0600);
MODULE_PARM_DESC(enable_pc8, "Enable support for low power package C states (PC8+) (default: true)");
int i915_pc8_timeout __read_mostly = 5000;
module_param_named(pc8_timeout, i915_pc8_timeout, int, 0600);
MODULE_PARM_DESC(pc8_timeout, "Number of msecs of idleness required to enter PC8+ (default: 5000)");
bool i915_prefault_disable __read_mostly;
module_param_named(prefault_disable, i915_prefault_disable, bool, 0600);
MODULE_PARM_DESC(prefault_disable,
"Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only.");
static struct drm_driver driver;
#define GEN_DEFAULT_PIPEOFFSETS \
.pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \
.trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \
TRANSCODER_C_OFFSET, TRANSCODER_EDP_OFFSET }, \
.dpll_offsets = { DPLL_A_OFFSET, DPLL_B_OFFSET }, \
.dpll_md_offsets = { DPLL_A_MD_OFFSET, DPLL_B_MD_OFFSET }, \
.palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET }
static const struct intel_device_info intel_i830_info = {
.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_845g_info = {
.gen = 2, .num_pipes = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i85x_info = {
......@@ -174,18 +70,21 @@ static const struct intel_device_info intel_i85x_info = {
.has_overlay = 1, .overlay_needs_physical = 1,
.has_fbc = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i865g_info = {
.gen = 2, .num_pipes = 1,
.has_overlay = 1, .overlay_needs_physical = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i915g_info = {
.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i915gm_info = {
.gen = 3, .is_mobile = 1, .num_pipes = 2,
......@@ -194,11 +93,13 @@ static const struct intel_device_info intel_i915gm_info = {
.supports_tv = 1,
.has_fbc = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i945g_info = {
.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
.has_overlay = 1, .overlay_needs_physical = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i945gm_info = {
.gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
......@@ -207,6 +108,7 @@ static const struct intel_device_info intel_i945gm_info = {
.supports_tv = 1,
.has_fbc = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i965g_info = {
......@@ -214,6 +116,7 @@ static const struct intel_device_info intel_i965g_info = {
.has_hotplug = 1,
.has_overlay = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_i965gm_info = {
......@@ -222,6 +125,7 @@ static const struct intel_device_info intel_i965gm_info = {
.has_overlay = 1,
.supports_tv = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_g33_info = {
......@@ -229,12 +133,14 @@ static const struct intel_device_info intel_g33_info = {
.need_gfx_hws = 1, .has_hotplug = 1,
.has_overlay = 1,
.ring_mask = RENDER_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_g45_info = {
.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
.has_pipe_cxsr = 1, .has_hotplug = 1,
.ring_mask = RENDER_RING | BSD_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_gm45_info = {
......@@ -243,18 +149,21 @@ static const struct intel_device_info intel_gm45_info = {
.has_pipe_cxsr = 1, .has_hotplug = 1,
.supports_tv = 1,
.ring_mask = RENDER_RING | BSD_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_pineview_info = {
.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_overlay = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_ironlake_d_info = {
.gen = 5, .num_pipes = 2,
.need_gfx_hws = 1, .has_hotplug = 1,
.ring_mask = RENDER_RING | BSD_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_ironlake_m_info = {
......@@ -262,6 +171,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
.need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 1,
.ring_mask = RENDER_RING | BSD_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_sandybridge_d_info = {
......@@ -270,6 +180,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
.has_fbc = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
.has_llc = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_sandybridge_m_info = {
......@@ -278,6 +189,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_fbc = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
.has_llc = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
#define GEN7_FEATURES \
......@@ -290,18 +202,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
static const struct intel_device_info intel_ivybridge_d_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_ivybridge_m_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
.is_mobile = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_ivybridge_q_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
.num_pipes = 0, /* legal, last one wins */
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_valleyview_m_info = {
......@@ -312,6 +227,7 @@ static const struct intel_device_info intel_valleyview_m_info = {
.display_mmio_offset = VLV_DISPLAY_BASE,
.has_fbc = 0, /* legal, last one wins */
.has_llc = 0, /* legal, last one wins */
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_valleyview_d_info = {
......@@ -321,6 +237,7 @@ static const struct intel_device_info intel_valleyview_d_info = {
.display_mmio_offset = VLV_DISPLAY_BASE,
.has_fbc = 0, /* legal, last one wins */
.has_llc = 0, /* legal, last one wins */
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_haswell_d_info = {
......@@ -329,6 +246,7 @@ static const struct intel_device_info intel_haswell_d_info = {
.has_ddi = 1,
.has_fpga_dbg = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_haswell_m_info = {
......@@ -338,6 +256,7 @@ static const struct intel_device_info intel_haswell_m_info = {
.has_ddi = 1,
.has_fpga_dbg = 1,
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_broadwell_d_info = {
......@@ -346,6 +265,7 @@ static const struct intel_device_info intel_broadwell_d_info = {
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
.has_llc = 1,
.has_ddi = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
static const struct intel_device_info intel_broadwell_m_info = {
......@@ -354,6 +274,7 @@ static const struct intel_device_info intel_broadwell_m_info = {
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
.has_llc = 1,
.has_ddi = 1,
GEN_DEFAULT_PIPEOFFSETS,
};
/*
......@@ -482,12 +403,12 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
/* Until we get further testing... */
if (IS_GEN8(dev)) {
WARN_ON(!i915_preliminary_hw_support);
WARN_ON(!i915.preliminary_hw_support);
return false;
}
if (i915_semaphores >= 0)
return i915_semaphores;
if (i915.semaphores >= 0)
return i915.semaphores;
#ifdef CONFIG_INTEL_IOMMU
/* Enable semaphores on SNB when IO remapping is off */
......@@ -643,6 +564,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
/* KMS EnterVT equivalent */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_init_pch_refclk(dev);
drm_mode_config_reset(dev);
mutex_lock(&dev->struct_mutex);
......@@ -655,7 +577,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
intel_modeset_init_hw(dev);
drm_modeset_lock_all(dev);
drm_mode_config_reset(dev);
intel_modeset_setup_hw_state(dev, true);
drm_modeset_unlock_all(dev);
......@@ -752,7 +673,7 @@ int i915_reset(struct drm_device *dev)
bool simulated;
int ret;
if (!i915_try_reset)
if (!i915.reset)
return 0;
mutex_lock(&dev->struct_mutex);
......@@ -807,6 +728,17 @@ int i915_reset(struct drm_device *dev)
drm_irq_uninstall(dev);
drm_irq_install(dev);
/* rps/rc6 re-init is necessary to restore state lost after the
* reset and the re-install of drm irq. Skip for ironlake per
* previous concerns that it doesn't respond well to some forms
* of re-init after reset. */
if (INTEL_INFO(dev)->gen > 5) {
mutex_lock(&dev->struct_mutex);
intel_enable_gt_powersave(dev);
mutex_unlock(&dev->struct_mutex);
}
intel_hpd_init(dev);
} else {
mutex_unlock(&dev->struct_mutex);
......@@ -820,7 +752,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct intel_device_info *intel_info =
(struct intel_device_info *) ent->driver_data;
if (IS_PRELIMINARY_HW(intel_info) && !i915_preliminary_hw_support) {
if (IS_PRELIMINARY_HW(intel_info) && !i915.preliminary_hw_support) {
DRM_INFO("This hardware requires preliminary hardware support.\n"
"See CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT, and/or modparam preliminary_hw_support\n");
return -ENODEV;
......@@ -1051,14 +983,14 @@ static int __init i915_init(void)
* the default behavior.
*/
#if defined(CONFIG_DRM_I915_KMS)
if (i915_modeset != 0)
if (i915.modeset != 0)
driver.driver_features |= DRIVER_MODESET;
#endif
if (i915_modeset == 1)
if (i915.modeset == 1)
driver.driver_features |= DRIVER_MODESET;
#ifdef CONFIG_VGA_CONSOLE
if (vgacon_text_force() && i915_modeset == -1)
if (vgacon_text_force() && i915.modeset == -1)
driver.driver_features &= ~DRIVER_MODESET;
#endif
......
此差异已折叠。
此差异已折叠。
......@@ -93,11 +93,19 @@
* I've seen in a spec to date, and that was a workaround for a non-shipping
* part. It should be safe to decrease this, but it's more future proof as is.
*/
#define CONTEXT_ALIGN (64<<10)
#define GEN6_CONTEXT_ALIGN (64<<10)
#define GEN7_CONTEXT_ALIGN 4096
static struct i915_hw_context *
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
static int do_switch(struct i915_hw_context *to);
static int do_switch(struct intel_ring_buffer *ring,
struct i915_hw_context *to);
static size_t get_context_alignment(struct drm_device *dev)
{
if (IS_GEN6(dev))
return GEN6_CONTEXT_ALIGN;
return GEN7_CONTEXT_ALIGN;
}
static int get_context_size(struct drm_device *dev)
{
......@@ -131,14 +139,43 @@ void i915_gem_context_free(struct kref *ctx_ref)
{
struct i915_hw_context *ctx = container_of(ctx_ref,
typeof(*ctx), ref);
struct i915_hw_ppgtt *ppgtt = NULL;
list_del(&ctx->link);
/* We refcount even the aliasing PPGTT to keep the code symmetric */
if (USES_PPGTT(ctx->obj->base.dev))
ppgtt = ctx_to_ppgtt(ctx);
/* XXX: Free up the object before tearing down the address space, in
* case we're bound in the PPGTT */
drm_gem_object_unreference(&ctx->obj->base);
if (ppgtt)
kref_put(&ppgtt->ref, ppgtt_release);
list_del(&ctx->link);
kfree(ctx);
}
static struct i915_hw_ppgtt *
create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx)
{
struct i915_hw_ppgtt *ppgtt;
int ret;
ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
if (!ppgtt)
return ERR_PTR(-ENOMEM);
ret = i915_gem_init_ppgtt(dev, ppgtt);
if (ret) {
kfree(ppgtt);
return ERR_PTR(ret);
}
return ppgtt;
}
static struct i915_hw_context *
create_hw_context(struct drm_device *dev,
__create_hw_context(struct drm_device *dev,
struct drm_i915_file_private *file_priv)
{
struct drm_i915_private *dev_priv = dev->dev_private;
......@@ -166,18 +203,13 @@ create_hw_context(struct drm_device *dev,
goto err_out;
}
/* The ring associated with the context object is handled by the normal
* object tracking code. We give an initial ring value simple to pass an
* assertion in the context switch code.
*/
ctx->ring = &dev_priv->ring[RCS];
list_add_tail(&ctx->link, &dev_priv->context_list);
/* Default context will never have a file_priv */
if (file_priv == NULL)
return ctx;
ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0,
GFP_KERNEL);
if (ret < 0)
goto err_out;
......@@ -196,67 +228,138 @@ create_hw_context(struct drm_device *dev,
return ERR_PTR(ret);
}
static inline bool is_default_context(struct i915_hw_context *ctx)
{
return (ctx == ctx->ring->default_context);
}
/**
* The default context needs to exist per ring that uses contexts. It stores the
* context state of the GPU for applications that don't utilize HW contexts, as
* well as an idle case.
*/
static int create_default_context(struct drm_i915_private *dev_priv)
static struct i915_hw_context *
i915_gem_create_context(struct drm_device *dev,
struct drm_i915_file_private *file_priv,
bool create_vm)
{
const bool is_global_default_ctx = file_priv == NULL;
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_hw_context *ctx;
int ret;
int ret = 0;
BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
ctx = create_hw_context(dev_priv->dev, NULL);
ctx = __create_hw_context(dev, file_priv);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
/* We may need to do things with the shrinker which require us to
* immediately switch back to the default context. This can cause a
* problem as pinning the default context also requires GTT space which
* may not be available. To avoid this we always pin the
* default context.
*/
ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false);
if (ret) {
DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
goto err_destroy;
}
return ctx;
ret = do_switch(ctx);
if (ret) {
DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
goto err_unpin;
if (is_global_default_ctx) {
/* We may need to do things with the shrinker which
* require us to immediately switch back to the default
* context. This can cause a problem as pinning the
* default context also requires GTT space which may not
* be available. To avoid this we always pin the default
* context.
*/
ret = i915_gem_obj_ggtt_pin(ctx->obj,
get_context_alignment(dev),
false, false);
if (ret) {
DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
goto err_destroy;
}
}
dev_priv->ring[RCS].default_context = ctx;
if (create_vm) {
struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
if (IS_ERR_OR_NULL(ppgtt)) {
DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
PTR_ERR(ppgtt));
ret = PTR_ERR(ppgtt);
goto err_unpin;
} else
ctx->vm = &ppgtt->base;
/* This case is reserved for the global default context and
* should only happen once. */
if (is_global_default_ctx) {
if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
ret = -EEXIST;
goto err_unpin;
}
dev_priv->mm.aliasing_ppgtt = ppgtt;
}
} else if (USES_PPGTT(dev)) {
/* For platforms which only have aliasing PPGTT, we fake the
* address space and refcounting. */
ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
} else
ctx->vm = &dev_priv->gtt.base;
DRM_DEBUG_DRIVER("Default HW context loaded\n");
return 0;
return ctx;
err_unpin:
i915_gem_object_unpin(ctx->obj);
if (is_global_default_ctx)
i915_gem_object_ggtt_unpin(ctx->obj);
err_destroy:
i915_gem_context_unreference(ctx);
return ret;
return ERR_PTR(ret);
}
void i915_gem_context_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring;
int i;
if (!HAS_HW_CONTEXTS(dev))
return;
/* Prevent the hardware from restoring the last context (which hung) on
* the next switch */
for (i = 0; i < I915_NUM_RINGS; i++) {
struct i915_hw_context *dctx;
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
/* Do a fake switch to the default context */
ring = &dev_priv->ring[i];
dctx = ring->default_context;
if (WARN_ON(!dctx))
continue;
if (!ring->last_context)
continue;
if (ring->last_context == dctx)
continue;
if (i == RCS) {
WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj,
get_context_alignment(dev),
false, false));
/* Fake a finish/inactive */
dctx->obj->base.write_domain = 0;
dctx->obj->active = 0;
}
i915_gem_context_unreference(ring->last_context);
i915_gem_context_reference(dctx);
ring->last_context = dctx;
}
}
int i915_gem_context_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
struct intel_ring_buffer *ring;
int i;
if (!HAS_HW_CONTEXTS(dev))
return 0;
/* If called from reset, or thaw... we've been here already */
if (dev_priv->ring[RCS].default_context)
/* Init should only be called once per module load. Eventually the
* restriction on the context_disabled check can be loosened. */
if (WARN_ON(dev_priv->ring[RCS].default_context))
return 0;
dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
......@@ -266,11 +369,23 @@ int i915_gem_context_init(struct drm_device *dev)
return -E2BIG;
}
ret = create_default_context(dev_priv);
if (ret) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n",
ret);
return ret;
dev_priv->ring[RCS].default_context =
i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) {
DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n",
PTR_ERR(dev_priv->ring[RCS].default_context));
return PTR_ERR(dev_priv->ring[RCS].default_context);
}
for (i = RCS + 1; i < I915_NUM_RINGS; i++) {
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
ring = &dev_priv->ring[i];
/* NB: RCS will hold a ref for all rings */
ring->default_context = dev_priv->ring[RCS].default_context;
}
DRM_DEBUG_DRIVER("HW context support initialized\n");
......@@ -281,6 +396,7 @@ void i915_gem_context_fini(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
int i;
if (!HAS_HW_CONTEXTS(dev))
return;
......@@ -300,59 +416,129 @@ void i915_gem_context_fini(struct drm_device *dev)
if (dev_priv->ring[RCS].last_context == dctx) {
/* Fake switch to NULL context */
WARN_ON(dctx->obj->active);
i915_gem_object_unpin(dctx->obj);
i915_gem_object_ggtt_unpin(dctx->obj);
i915_gem_context_unreference(dctx);
dev_priv->ring[RCS].last_context = NULL;
}
i915_gem_object_unpin(dctx->obj);
for (i = 0; i < I915_NUM_RINGS; i++) {
struct intel_ring_buffer *ring = &dev_priv->ring[i];
if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
continue;
if (ring->last_context)
i915_gem_context_unreference(ring->last_context);
ring->default_context = NULL;
ring->last_context = NULL;
}
i915_gem_object_ggtt_unpin(dctx->obj);
i915_gem_context_unreference(dctx);
dev_priv->ring[RCS].default_context = NULL;
dev_priv->ring[RCS].last_context = NULL;
dev_priv->mm.aliasing_ppgtt = NULL;
}
int i915_gem_context_enable(struct drm_i915_private *dev_priv)
{
struct intel_ring_buffer *ring;
int ret, i;
if (!HAS_HW_CONTEXTS(dev_priv->dev))
return 0;
/* This is the only place the aliasing PPGTT gets enabled, which means
* it has to happen before we bail on reset */
if (dev_priv->mm.aliasing_ppgtt) {
struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
ppgtt->enable(ppgtt);
}
/* FIXME: We should make this work, even in reset */
if (i915_reset_in_progress(&dev_priv->gpu_error))
return 0;
BUG_ON(!dev_priv->ring[RCS].default_context);
for_each_ring(ring, dev_priv, i) {
ret = do_switch(ring, ring->default_context);
if (ret)
return ret;
}
return 0;
}
static int context_idr_cleanup(int id, void *p, void *data)
{
struct i915_hw_context *ctx = p;
BUG_ON(id == DEFAULT_CONTEXT_ID);
/* Ignore the default context because close will handle it */
if (i915_gem_context_is_default(ctx))
return 0;
i915_gem_context_unreference(ctx);
return 0;
}
struct i915_ctx_hang_stats *
i915_gem_context_get_hang_stats(struct drm_device *dev,
struct drm_file *file,
u32 id)
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
struct i915_hw_context *ctx;
struct drm_i915_private *dev_priv = dev->dev_private;
if (id == DEFAULT_CONTEXT_ID)
return &file_priv->hang_stats;
if (!HAS_HW_CONTEXTS(dev)) {
/* Cheat for hang stats */
file_priv->private_default_ctx =
kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL);
if (!HAS_HW_CONTEXTS(dev))
return ERR_PTR(-ENOENT);
if (file_priv->private_default_ctx == NULL)
return -ENOMEM;
ctx = i915_gem_context_get(file->driver_priv, id);
if (ctx == NULL)
return ERR_PTR(-ENOENT);
file_priv->private_default_ctx->vm = &dev_priv->gtt.base;
return 0;
}
return &ctx->hang_stats;
idr_init(&file_priv->context_idr);
mutex_lock(&dev->struct_mutex);
file_priv->private_default_ctx =
i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
mutex_unlock(&dev->struct_mutex);
if (IS_ERR(file_priv->private_default_ctx)) {
idr_destroy(&file_priv->context_idr);
return PTR_ERR(file_priv->private_default_ctx);
}
return 0;
}
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
if (!HAS_HW_CONTEXTS(dev)) {
kfree(file_priv->private_default_ctx);
return;
}
idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
i915_gem_context_unreference(file_priv->private_default_ctx);
idr_destroy(&file_priv->context_idr);
}
static struct i915_hw_context *
struct i915_hw_context *
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
{
return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
struct i915_hw_context *ctx;
if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev))
return file_priv->private_default_ctx;
ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
if (!ctx)
return ERR_PTR(-ENOENT);
return ctx;
}
static inline int
......@@ -390,7 +576,10 @@ mi_set_context(struct intel_ring_buffer *ring,
MI_SAVE_EXT_STATE_EN |
MI_RESTORE_EXT_STATE_EN |
hw_flags);
/* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */
/*
* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
* WaMiSetContext_Hang:snb,ivb,vlv
*/
intel_ring_emit(ring, MI_NOOP);
if (IS_GEN7(ring->dev))
......@@ -403,21 +592,31 @@ mi_set_context(struct intel_ring_buffer *ring,
return ret;
}
static int do_switch(struct i915_hw_context *to)
static int do_switch(struct intel_ring_buffer *ring,
struct i915_hw_context *to)
{
struct intel_ring_buffer *ring = to->ring;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
struct i915_hw_context *from = ring->last_context;
struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
u32 hw_flags = 0;
int ret, i;
BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
if (from != NULL && ring == &dev_priv->ring[RCS]) {
BUG_ON(from->obj == NULL);
BUG_ON(!i915_gem_obj_is_pinned(from->obj));
}
if (from == to && !to->remap_slice)
if (from == to && from->last_ring == ring && !to->remap_slice)
return 0;
ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false);
if (ret)
return ret;
/* Trying to pin first makes error handling easier. */
if (ring == &dev_priv->ring[RCS]) {
ret = i915_gem_obj_ggtt_pin(to->obj,
get_context_alignment(ring->dev),
false, false);
if (ret)
return ret;
}
/*
* Pin can switch back to the default context if we end up calling into
......@@ -426,6 +625,18 @@ static int do_switch(struct i915_hw_context *to)
*/
from = ring->last_context;
if (USES_FULL_PPGTT(ring->dev)) {
ret = ppgtt->switch_mm(ppgtt, ring, false);
if (ret)
goto unpin_out;
}
if (ring != &dev_priv->ring[RCS]) {
if (from)
i915_gem_context_unreference(from);
goto done;
}
/*
* Clear this page out of any CPU caches for coherent swap-in/out. Note
* that thanks to write = false in this call and us not setting any gpu
......@@ -435,22 +646,21 @@ static int do_switch(struct i915_hw_context *to)
* XXX: We need a real interface to do this instead of trickery.
*/
ret = i915_gem_object_set_to_gtt_domain(to->obj, false);
if (ret) {
i915_gem_object_unpin(to->obj);
return ret;
}
if (ret)
goto unpin_out;
if (!to->obj->has_global_gtt_mapping)
i915_gem_gtt_bind_object(to->obj, to->obj->cache_level);
if (!to->obj->has_global_gtt_mapping) {
struct i915_vma *vma = i915_gem_obj_to_vma(to->obj,
&dev_priv->gtt.base);
vma->bind_vma(vma, to->obj->cache_level, GLOBAL_BIND);
}
if (!to->is_initialized || is_default_context(to))
if (!to->is_initialized || i915_gem_context_is_default(to))
hw_flags |= MI_RESTORE_INHIBIT;
ret = mi_set_context(ring, to, hw_flags);
if (ret) {
i915_gem_object_unpin(to->obj);
return ret;
}
if (ret)
goto unpin_out;
for (i = 0; i < MAX_L3_SLICES; i++) {
if (!(to->remap_slice & (1<<i)))
......@@ -484,15 +694,23 @@ static int do_switch(struct i915_hw_context *to)
BUG_ON(from->obj->ring != ring);
/* obj is kept alive until the next request by its active ref */
i915_gem_object_unpin(from->obj);
i915_gem_object_ggtt_unpin(from->obj);
i915_gem_context_unreference(from);
}
to->is_initialized = true;
done:
i915_gem_context_reference(to);
ring->last_context = to;
to->is_initialized = true;
to->last_ring = ring;
return 0;
unpin_out:
if (ring->id == RCS)
i915_gem_object_ggtt_unpin(to->obj);
return ret;
}
/**
......@@ -508,31 +726,19 @@ static int do_switch(struct i915_hw_context *to)
*/
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file,
int to_id)
struct i915_hw_context *to)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
struct i915_hw_context *to;
if (!HAS_HW_CONTEXTS(ring->dev))
return 0;
WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
if (ring != &dev_priv->ring[RCS])
return 0;
if (to_id == DEFAULT_CONTEXT_ID) {
to = ring->default_context;
} else {
if (file == NULL)
return -EINVAL;
BUG_ON(file && to == NULL);
to = i915_gem_context_get(file->driver_priv, to_id);
if (to == NULL)
return -ENOENT;
}
/* We have the fake context, but don't supports switching. */
if (!HAS_HW_CONTEXTS(ring->dev))
return 0;
return do_switch(to);
return do_switch(ring, to);
}
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
......@@ -553,7 +759,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
if (ret)
return ret;
ctx = create_hw_context(dev, file_priv);
ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
mutex_unlock(&dev->struct_mutex);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
......@@ -575,14 +781,17 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
if (!(dev->driver->driver_features & DRIVER_GEM))
return -ENODEV;
if (args->ctx_id == DEFAULT_CONTEXT_ID)
return -ENOENT;
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
ctx = i915_gem_context_get(file_priv, args->ctx_id);
if (!ctx) {
if (IS_ERR(ctx)) {
mutex_unlock(&dev->struct_mutex);
return -ENOENT;
return PTR_ERR(ctx);
}
idr_remove(&ctx->file_priv->context_idr, ctx->id);
......
......@@ -36,7 +36,7 @@
static bool
mark_free(struct i915_vma *vma, struct list_head *unwind)
{
if (vma->obj->pin_count)
if (vma->pin_count)
return false;
if (WARN_ON(!list_empty(&vma->exec_list)))
......@@ -46,6 +46,25 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
return drm_mm_scan_add_block(&vma->node);
}
/**
* i915_gem_evict_something - Evict vmas to make room for binding a new one
* @dev: drm_device
* @vm: address space to evict from
* @size: size of the desired free space
* @alignment: alignment constraint of the desired free space
* @cache_level: cache_level for the desired space
* @mappable: whether the free space must be mappable
* @nonblocking: whether evicting active objects is allowed or not
*
* This function will try to evict vmas until a free space satisfying the
* requirements is found. Callers must check first whether any such hole exists
* already before calling this function.
*
* This function is used by the object/vma binding code.
*
* To clarify: This is for freeing up virtual address space, not for freeing
* memory in e.g. the shrinker.
*/
int
i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
int min_size, unsigned alignment, unsigned cache_level,
......@@ -177,19 +196,19 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
}
/**
* i915_gem_evict_vm - Try to free up VM space
* i915_gem_evict_vm - Evict all idle vmas from a vm
*
* @vm: Address space to evict from
* @vm: Address space to cleanse
* @do_idle: Boolean directing whether to idle first.
*
* VM eviction is about freeing up virtual address space. If one wants fine
* grained eviction, they should see evict something for more details. In terms
* of freeing up actual system memory, this function may not accomplish the
* desired result. An object may be shared in multiple address space, and this
* function will not assert those objects be freed.
* This function evicts all idles vmas from a vm. If all unpinned vmas should be
* evicted the @do_idle needs to be set to true.
*
* Using do_idle will result in a more complete eviction because it retires, and
* inactivates current BOs.
* This is used by the execbuf code as a last-ditch effort to defragment the
* address space.
*
* To clarify: This is for freeing up virtual address space, not for freeing
* memory in e.g. the shrinker.
*/
int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
{
......@@ -207,12 +226,20 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
}
list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
if (vma->obj->pin_count == 0)
if (vma->pin_count == 0)
WARN_ON(i915_vma_unbind(vma));
return 0;
}
/**
* i915_gem_evict_everything - Try to evict all objects
* @dev: Device to evict objects for
*
* This functions tries to evict all gem objects from all address spaces. Used
* by the shrinker as a last-ditch effort and for suspend, before releasing the
* backing storage of all unbound objects.
*/
int
i915_gem_evict_everything(struct drm_device *dev)
{
......
......@@ -91,6 +91,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
struct i915_address_space *vm,
struct drm_file *file)
{
struct drm_i915_private *dev_priv = vm->dev->dev_private;
struct drm_i915_gem_object *obj;
struct list_head objects;
int i, ret;
......@@ -125,6 +126,20 @@ eb_lookup_vmas(struct eb_vmas *eb,
i = 0;
while (!list_empty(&objects)) {
struct i915_vma *vma;
struct i915_address_space *bind_vm = vm;
if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT &&
USES_FULL_PPGTT(vm->dev)) {
ret = -EINVAL;
goto err;
}
/* If we have secure dispatch, or the userspace assures us that
* they know what they're doing, use the GGTT VM.
*/
if (((args->flags & I915_EXEC_SECURE) &&
(i == (args->buffer_count - 1))))
bind_vm = &dev_priv->gtt.base;
obj = list_first_entry(&objects,
struct drm_i915_gem_object,
......@@ -138,7 +153,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
* from the (obj, vm) we don't run the risk of creating
* duplicated vmas for the same vm.
*/
vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm);
if (IS_ERR(vma)) {
DRM_DEBUG("Failed to lookup VMA\n");
ret = PTR_ERR(vma);
......@@ -217,7 +232,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
i915_gem_object_unpin_fence(obj);
if (entry->flags & __EXEC_OBJECT_HAS_PIN)
i915_gem_object_unpin(obj);
vma->pin_count--;
entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
}
......@@ -327,8 +342,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
static int
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
struct eb_vmas *eb,
struct drm_i915_gem_relocation_entry *reloc,
struct i915_address_space *vm)
struct drm_i915_gem_relocation_entry *reloc)
{
struct drm_device *dev = obj->base.dev;
struct drm_gem_object *target_obj;
......@@ -352,8 +366,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
if (unlikely(IS_GEN6(dev) &&
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
!target_i915_obj->has_global_gtt_mapping)) {
i915_gem_gtt_bind_object(target_i915_obj,
target_i915_obj->cache_level);
struct i915_vma *vma =
list_first_entry(&target_i915_obj->vma_list,
typeof(*vma), vma_link);
vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND);
}
/* Validate that the target is in a valid r/w GPU domain */
......@@ -451,8 +467,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
do {
u64 offset = r->presumed_offset;
ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r,
vma->vm);
ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r);
if (ret)
return ret;
......@@ -481,8 +496,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma,
int i, ret;
for (i = 0; i < entry->relocation_count; i++) {
ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i],
vma->vm);
ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i]);
if (ret)
return ret;
}
......@@ -527,11 +541,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
struct intel_ring_buffer *ring,
bool *need_reloc)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_object *obj = vma->obj;
struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
bool need_fence, need_mappable;
struct drm_i915_gem_object *obj = vma->obj;
u32 flags = (entry->flags & EXEC_OBJECT_NEEDS_GTT) &&
!vma->obj->has_global_gtt_mapping ? GLOBAL_BIND : 0;
int ret;
need_fence =
......@@ -560,14 +575,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
}
}
/* Ensure ppgtt mapping exists if needed */
if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
obj, obj->cache_level);
obj->has_aliasing_ppgtt_mapping = 1;
}
if (entry->offset != vma->node.start) {
entry->offset = vma->node.start;
*need_reloc = true;
......@@ -578,9 +585,7 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER;
}
if (entry->flags & EXEC_OBJECT_NEEDS_GTT &&
!obj->has_global_gtt_mapping)
i915_gem_gtt_bind_object(obj, obj->cache_level);
vma->bind_vma(vma, obj->cache_level, flags);
return 0;
}
......@@ -891,7 +896,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
if (!access_ok(VERIFY_WRITE, ptr, length))
return -EFAULT;
if (likely(!i915_prefault_disable)) {
if (likely(!i915.prefault_disable)) {
if (fault_in_multipages_readable(ptr, length))
return -EFAULT;
}
......@@ -900,22 +905,27 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
return 0;
}
static int
static struct i915_hw_context *
i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
const u32 ctx_id)
struct intel_ring_buffer *ring, const u32 ctx_id)
{
struct i915_hw_context *ctx = NULL;
struct i915_ctx_hang_stats *hs;
hs = i915_gem_context_get_hang_stats(dev, file, ctx_id);
if (IS_ERR(hs))
return PTR_ERR(hs);
if (ring->id != RCS && ctx_id != DEFAULT_CONTEXT_ID)
return ERR_PTR(-EINVAL);
ctx = i915_gem_context_get(file->driver_priv, ctx_id);
if (IS_ERR(ctx))
return ctx;
hs = &ctx->hang_stats;
if (hs->banned) {
DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id);
return -EIO;
return ERR_PTR(-EIO);
}
return 0;
return ctx;
}
static void
......@@ -939,7 +949,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
if (obj->base.write_domain) {
obj->dirty = 1;
obj->last_write_seqno = intel_ring_get_seqno(ring);
if (obj->pin_count) /* check for potential scanout */
/* check for potential scanout */
if (i915_gem_obj_ggtt_bound(obj) &&
i915_gem_obj_to_ggtt(obj)->pin_count)
intel_mark_fb_busy(obj, ring);
}
......@@ -989,16 +1001,17 @@ static int
i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file,
struct drm_i915_gem_execbuffer2 *args,
struct drm_i915_gem_exec_object2 *exec,
struct i915_address_space *vm)
struct drm_i915_gem_exec_object2 *exec)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct eb_vmas *eb;
struct drm_i915_gem_object *batch_obj;
struct drm_clip_rect *cliprects = NULL;
struct intel_ring_buffer *ring;
struct i915_hw_context *ctx;
struct i915_address_space *vm;
const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
u32 exec_start, exec_len;
u32 exec_start = args->batch_start_offset, exec_len;
u32 mask, flags;
int ret, mode, i;
bool need_relocs;
......@@ -1020,41 +1033,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (args->flags & I915_EXEC_IS_PINNED)
flags |= I915_DISPATCH_PINNED;
switch (args->flags & I915_EXEC_RING_MASK) {
case I915_EXEC_DEFAULT:
case I915_EXEC_RENDER:
ring = &dev_priv->ring[RCS];
break;
case I915_EXEC_BSD:
ring = &dev_priv->ring[VCS];
if (ctx_id != DEFAULT_CONTEXT_ID) {
DRM_DEBUG("Ring %s doesn't support contexts\n",
ring->name);
return -EPERM;
}
break;
case I915_EXEC_BLT:
ring = &dev_priv->ring[BCS];
if (ctx_id != DEFAULT_CONTEXT_ID) {
DRM_DEBUG("Ring %s doesn't support contexts\n",
ring->name);
return -EPERM;
}
break;
case I915_EXEC_VEBOX:
ring = &dev_priv->ring[VECS];
if (ctx_id != DEFAULT_CONTEXT_ID) {
DRM_DEBUG("Ring %s doesn't support contexts\n",
ring->name);
return -EPERM;
}
break;
default:
if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) {
DRM_DEBUG("execbuf with unknown ring: %d\n",
(int)(args->flags & I915_EXEC_RING_MASK));
return -EINVAL;
}
if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
ring = &dev_priv->ring[RCS];
else
ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1];
if (!intel_ring_initialized(ring)) {
DRM_DEBUG("execbuf with invalid ring: %d\n",
(int)(args->flags & I915_EXEC_RING_MASK));
......@@ -1136,11 +1125,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto pre_mutex_err;
}
ret = i915_gem_validate_context(dev, file, ctx_id);
if (ret) {
ctx = i915_gem_validate_context(dev, file, ring, ctx_id);
if (IS_ERR(ctx)) {
mutex_unlock(&dev->struct_mutex);
ret = PTR_ERR(ctx);
goto pre_mutex_err;
}
}
i915_gem_context_reference(ctx);
vm = ctx->vm;
if (!USES_FULL_PPGTT(dev))
vm = &dev_priv->gtt.base;
eb = eb_create(args);
if (eb == NULL) {
......@@ -1187,14 +1183,25 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
/* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
* batch" bit. Hence we need to pin secure batches into the global gtt.
* hsw should have this fixed, but bdw mucks it up again. */
if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping)
i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level);
if (flags & I915_DISPATCH_SECURE &&
!batch_obj->has_global_gtt_mapping) {
/* When we have multiple VMs, we'll need to make sure that we
* allocate space first */
struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj);
BUG_ON(!vma);
vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND);
}
if (flags & I915_DISPATCH_SECURE)
exec_start += i915_gem_obj_ggtt_offset(batch_obj);
else
exec_start += i915_gem_obj_offset(batch_obj, vm);
ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas);
if (ret)
goto err;
ret = i915_switch_context(ring, file, ctx_id);
ret = i915_switch_context(ring, file, ctx);
if (ret)
goto err;
......@@ -1219,8 +1226,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto err;
}
exec_start = i915_gem_obj_offset(batch_obj, vm) +
args->batch_start_offset;
exec_len = args->batch_len;
if (cliprects) {
for (i = 0; i < args->num_cliprects; i++) {
......@@ -1249,6 +1255,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
err:
/* the request owns the ref now */
i915_gem_context_unreference(ctx);
eb_destroy(eb);
mutex_unlock(&dev->struct_mutex);
......@@ -1270,7 +1278,6 @@ int
i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_execbuffer *args = data;
struct drm_i915_gem_execbuffer2 exec2;
struct drm_i915_gem_exec_object *exec_list = NULL;
......@@ -1326,8 +1333,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
exec2.flags = I915_EXEC_RENDER;
i915_execbuffer2_set_context_id(exec2, 0);
ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list,
&dev_priv->gtt.base);
ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
if (!ret) {
/* Copy the new buffer offsets back to the user's exec list. */
for (i = 0; i < args->buffer_count; i++)
......@@ -1353,7 +1359,6 @@ int
i915_gem_execbuffer2(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_execbuffer2 *args = data;
struct drm_i915_gem_exec_object2 *exec2_list = NULL;
int ret;
......@@ -1384,8 +1389,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
return -EFAULT;
}
ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list,
&dev_priv->gtt.base);
ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
if (!ret) {
/* Copy the new buffer offsets back to the user's exec list. */
ret = copy_to_user(to_user_ptr(args->buffers_ptr),
......
此差异已折叠。
......@@ -308,7 +308,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
return -EINVAL;
}
if (obj->pin_count || obj->framebuffer_references) {
if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
drm_gem_object_unreference_unlocked(&obj->base);
return -EBUSY;
}
......
此差异已折叠。
/*
* Copyright © 2014 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "i915_drv.h"
struct i915_params i915 __read_mostly = {
.modeset = -1,
.panel_ignore_lid = 1,
.powersave = 1,
.semaphores = -1,
.lvds_downclock = 0,
.lvds_channel_mode = 0,
.panel_use_ssc = -1,
.vbt_sdvo_panel_type = -1,
.enable_rc6 = -1,
.enable_fbc = -1,
.enable_hangcheck = true,
.enable_ppgtt = -1,
.enable_psr = 0,
.preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
.disable_power_well = 1,
.enable_ips = 1,
.fastboot = 0,
.enable_pc8 = 1,
.pc8_timeout = 5000,
.prefault_disable = 0,
.reset = true,
.invert_brightness = 0,
};
module_param_named(modeset, i915.modeset, int, 0400);
MODULE_PARM_DESC(modeset,
"Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
"1=on, -1=force vga console preference [default])");
module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600);
MODULE_PARM_DESC(panel_ignore_lid,
"Override lid status (0=autodetect, 1=autodetect disabled [default], "
"-1=force lid closed, -2=force lid open)");
module_param_named(powersave, i915.powersave, int, 0600);
MODULE_PARM_DESC(powersave,
"Enable powersavings, fbc, downclocking, etc. (default: true)");
module_param_named(semaphores, i915.semaphores, int, 0400);
MODULE_PARM_DESC(semaphores,
"Use semaphores for inter-ring sync "
"(default: -1 (use per-chip defaults))");
module_param_named(enable_rc6, i915.enable_rc6, int, 0400);
MODULE_PARM_DESC(enable_rc6,
"Enable power-saving render C-state 6. "
"Different stages can be selected via bitmask values "
"(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
"For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
"default: -1 (use per-chip default)");
module_param_named(enable_fbc, i915.enable_fbc, int, 0600);
MODULE_PARM_DESC(enable_fbc,
"Enable frame buffer compression for power savings "
"(default: -1 (use per-chip default))");
module_param_named(lvds_downclock, i915.lvds_downclock, int, 0400);
MODULE_PARM_DESC(lvds_downclock,
"Use panel (LVDS/eDP) downclocking for power savings "
"(default: false)");
module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600);
MODULE_PARM_DESC(lvds_channel_mode,
"Specify LVDS channel mode "
"(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
module_param_named(lvds_use_ssc, i915.panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc,
"Use Spread Spectrum Clock with panels [LVDS/eDP] "
"(default: auto from VBT)");
module_param_named(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600);
MODULE_PARM_DESC(vbt_sdvo_panel_type,
"Override/Ignore selection of SDVO panel mode in the VBT "
"(-2=ignore, -1=auto [default], index in VBT BIOS table)");
module_param_named(reset, i915.reset, bool, 0600);
MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644);
MODULE_PARM_DESC(enable_hangcheck,
"Periodically check GPU activity for detecting hangs. "
"WARNING: Disabling this can cause system wide hangs. "
"(default: true)");
module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400);
MODULE_PARM_DESC(enable_ppgtt,
"Override PPGTT usage. "
"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
module_param_named(enable_psr, i915.enable_psr, int, 0600);
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
module_param_named(preliminary_hw_support, i915.preliminary_hw_support, int, 0600);
MODULE_PARM_DESC(preliminary_hw_support,
"Enable preliminary hardware support.");
module_param_named(disable_power_well, i915.disable_power_well, int, 0600);
MODULE_PARM_DESC(disable_power_well,
"Disable the power well when possible (default: true)");
module_param_named(enable_ips, i915.enable_ips, int, 0600);
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
module_param_named(fastboot, i915.fastboot, bool, 0600);
MODULE_PARM_DESC(fastboot,
"Try to skip unnecessary mode sets at boot time (default: false)");
module_param_named(enable_pc8, i915.enable_pc8, int, 0600);
MODULE_PARM_DESC(enable_pc8,
"Enable support for low power package C states (PC8+) (default: true)");
module_param_named(pc8_timeout, i915.pc8_timeout, int, 0600);
MODULE_PARM_DESC(pc8_timeout,
"Number of msecs of idleness required to enter PC8+ (default: 5000)");
module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
MODULE_PARM_DESC(prefault_disable,
"Disable page prefaulting for pread/pwrite/reloc (default:false). "
"For developers only.");
module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
MODULE_PARM_DESC(invert_brightness,
"Invert backlight brightness "
"(-1 force normal, 0 machine defaults, 1 force inversion), please "
"report PCI device ID, subsystem vendor and subsystem device ID "
"to dri-devel@lists.freedesktop.org, if your machine needs it. "
"It will then be included in an upcoming module version.");
此差异已折叠。
......@@ -236,19 +236,9 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR);
}
/* Only regfile.save FBC state on the platform that supports FBC */
if (HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) {
dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
} else if (IS_GM45(dev)) {
dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
} else {
dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
}
}
/* save FBC interval */
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_save_vga(dev);
......@@ -300,18 +290,10 @@ static void i915_restore_display(struct drm_device *dev)
/* only restore FBC info on the platform that supports FBC*/
intel_disable_fbc(dev);
if (HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) {
I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
} else if (IS_GM45(dev)) {
I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
} else {
I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE);
I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE);
I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2);
I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
}
}
/* restore FBC interval */
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_restore_vga(dev);
......@@ -324,10 +306,6 @@ int i915_save_state(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
if (INTEL_INFO(dev)->gen <= 4)
pci_read_config_byte(dev->pdev, LBB,
&dev_priv->regfile.saveLBB);
mutex_lock(&dev->struct_mutex);
i915_save_display(dev);
......@@ -377,10 +355,6 @@ int i915_restore_state(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
if (INTEL_INFO(dev)->gen <= 4)
pci_write_config_byte(dev->pdev, LBB,
dev_priv->regfile.saveLBB);
mutex_lock(&dev->struct_mutex);
i915_gem_restore_fences(dev);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册