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

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

More in i915 for 4.12:

- designware i2c fixes from Hans de Goede, in a topic branch shared
  with other subsystems (maybe, they didn't confirm, but requested the
  pull)
- drop drm_panel usage from the intel dsi vbt panel (Jani)
- vblank evasion improvements and tracing (Maarten and Ville)
- clarify spinlock irq semantics again a bit (Tvrtko)
- new ->pwrite backend hook (right now just for shmem pageche writes),
  from Chris
- more planar/ccs work from Ville
- hotplug safe connector iterators everywhere
- userptr fixes (Chris)
- selftests for cache coloring eviction (Matthew Auld)
- extend debugfs drop_caches interface for shrinker testing (Chris)
- baytrail "the rps kills the machine" fix (Chris)
- use new atomic state iterators, a lot (Maarten)
- refactor guc/huc code some (Arkadiusz Hiler)
- tighten breadcrumbs rbtree a bit (Chris)
- improve wrap-around and time handling in rps residency counters
  (Mika)
- split reset-in-progress in two flags, backoff and handoff (Chris)
- other misc reset improvements from a few people
- bunch of vgpu interaction fixes with recent code changes
- misc stuff all over, as usual

* tag 'drm-intel-next-2017-03-20' of git://anongit.freedesktop.org/git/drm-intel: (144 commits)
  drm/i915: Update DRIVER_DATE to 20170320
  drm/i915: Initialise i915_gem_object_create_from_data() directly
  drm/i915: Correct error handling for i915_gem_object_create_from_data()
  drm/i915: i915_gem_object_create_from_data() doesn't require struct_mutex
  drm/i915: Retire an active batch pool object rather than allocate new
  drm/i915: Add i810/i815 pci-ids for completeness
  drm/i915: Skip execlists_dequeue() early if the list is empty
  drm/i915: Stop using obj->obj_exec_link outside of execbuf
  drm/i915: Squelch WARN for VLV_COUNTER_CONTROL
  drm/i915/glk: Enable pooled EUs for Geminilake
  drm/i915: Remove superfluous i915_add_request_no_flush() helper
  drm/i915/vgpu: Neuter forcewakes for VGPU more thoroughly
  drm/i915: Fix vGPU balloon for ggtt guard page
  drm/i915: Avoid use-after-free of ctx in request tracepoints
  drm/i915: Assert that the context pin_counts do not overflow
  drm/i915: Wait for reset to complete before returning from debugfs/i915_wedged
  drm/i915: Restore engine->submit_request before unwedging
  drm/i915: Move engine->submit_request selection to a vfunc
  drm/i915: Split I915_RESET_IN_PROGRESS into two flags
  drm/i915: make context status notifier head be per engine
  ...
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef IOSF_MBI_SYMS_H #ifndef IOSF_MBI_SYMS_H
#define IOSF_MBI_SYMS_H #define IOSF_MBI_SYMS_H
#include <linux/notifier.h>
#define MBI_MCR_OFFSET 0xD0 #define MBI_MCR_OFFSET 0xD0
#define MBI_MDR_OFFSET 0xD4 #define MBI_MDR_OFFSET 0xD4
#define MBI_MCRX_OFFSET 0xD8 #define MBI_MCRX_OFFSET 0xD8
...@@ -47,6 +49,10 @@ ...@@ -47,6 +49,10 @@
#define QRK_MBI_UNIT_MM 0x05 #define QRK_MBI_UNIT_MM 0x05
#define QRK_MBI_UNIT_SOC 0x31 #define QRK_MBI_UNIT_SOC 0x31
/* Action values for the pmic_bus_access_notifier functions */
#define MBI_PMIC_BUS_ACCESS_BEGIN 1
#define MBI_PMIC_BUS_ACCESS_END 2
#if IS_ENABLED(CONFIG_IOSF_MBI) #if IS_ENABLED(CONFIG_IOSF_MBI)
bool iosf_mbi_available(void); bool iosf_mbi_available(void);
...@@ -88,6 +94,65 @@ int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr); ...@@ -88,6 +94,65 @@ int iosf_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr);
*/ */
int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask); int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
/**
* iosf_mbi_punit_acquire() - Acquire access to the P-Unit
*
* One some systems the P-Unit accesses the PMIC to change various voltages
* through the same bus as other kernel drivers use for e.g. battery monitoring.
*
* If a driver sends requests to the P-Unit which require the P-Unit to access
* the PMIC bus while another driver is also accessing the PMIC bus various bad
* things happen.
*
* To avoid these problems this function must be called before accessing the
* P-Unit or the PMIC, be it through iosf_mbi* functions or through other means.
*
* Note on these systems the i2c-bus driver will request a sempahore from the
* P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing
* it, but this does not appear to be sufficient, we still need to avoid making
* certain P-Unit requests during the access window to avoid problems.
*
* This function locks a mutex, as such it may sleep.
*/
void iosf_mbi_punit_acquire(void);
/**
* iosf_mbi_punit_release() - Release access to the P-Unit
*/
void iosf_mbi_punit_release(void);
/**
* iosf_mbi_register_pmic_bus_access_notifier - Register PMIC bus notifier
*
* This function can be used by drivers which may need to acquire P-Unit
* managed resources from interrupt context, where iosf_mbi_punit_acquire()
* can not be used.
*
* This function allows a driver to register a notifier to get notified (in a
* process context) before other drivers start accessing the PMIC bus.
*
* This allows the driver to acquire any resources, which it may need during
* the window the other driver is accessing the PMIC, before hand.
*
* @nb: notifier_block to register
*/
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb);
/**
* iosf_mbi_register_pmic_bus_access_notifier - Unregister PMIC bus notifier
*
* @nb: notifier_block to unregister
*/
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb);
/**
* iosf_mbi_call_pmic_bus_access_notifier_chain - Call PMIC bus notifier chain
*
* @val: action to pass into listener's notifier_call function
* @v: data pointer to pass into listener's notifier_call function
*/
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v);
#else /* CONFIG_IOSF_MBI is not enabled */ #else /* CONFIG_IOSF_MBI is not enabled */
static inline static inline
bool iosf_mbi_available(void) bool iosf_mbi_available(void)
...@@ -115,6 +180,28 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask) ...@@ -115,6 +180,28 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
WARN(1, "IOSF_MBI driver not available"); WARN(1, "IOSF_MBI driver not available");
return -EPERM; return -EPERM;
} }
static inline void iosf_mbi_punit_acquire(void) {}
static inline void iosf_mbi_punit_release(void) {}
static inline
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
{
return 0;
}
static inline
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
{
return 0;
}
static inline
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
{
return 0;
}
#endif /* CONFIG_IOSF_MBI */ #endif /* CONFIG_IOSF_MBI */
#endif /* IOSF_MBI_SYMS_H */ #endif /* IOSF_MBI_SYMS_H */
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
static struct pci_dev *mbi_pdev; static struct pci_dev *mbi_pdev;
static DEFINE_SPINLOCK(iosf_mbi_lock); static DEFINE_SPINLOCK(iosf_mbi_lock);
static DEFINE_MUTEX(iosf_mbi_punit_mutex);
static BLOCKING_NOTIFIER_HEAD(iosf_mbi_pmic_bus_access_notifier);
static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset) static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
{ {
...@@ -190,6 +192,53 @@ bool iosf_mbi_available(void) ...@@ -190,6 +192,53 @@ bool iosf_mbi_available(void)
} }
EXPORT_SYMBOL(iosf_mbi_available); EXPORT_SYMBOL(iosf_mbi_available);
void iosf_mbi_punit_acquire(void)
{
mutex_lock(&iosf_mbi_punit_mutex);
}
EXPORT_SYMBOL(iosf_mbi_punit_acquire);
void iosf_mbi_punit_release(void)
{
mutex_unlock(&iosf_mbi_punit_mutex);
}
EXPORT_SYMBOL(iosf_mbi_punit_release);
int iosf_mbi_register_pmic_bus_access_notifier(struct notifier_block *nb)
{
int ret;
/* Wait for the bus to go inactive before registering */
mutex_lock(&iosf_mbi_punit_mutex);
ret = blocking_notifier_chain_register(
&iosf_mbi_pmic_bus_access_notifier, nb);
mutex_unlock(&iosf_mbi_punit_mutex);
return ret;
}
EXPORT_SYMBOL(iosf_mbi_register_pmic_bus_access_notifier);
int iosf_mbi_unregister_pmic_bus_access_notifier(struct notifier_block *nb)
{
int ret;
/* Wait for the bus to go inactive before unregistering */
mutex_lock(&iosf_mbi_punit_mutex);
ret = blocking_notifier_chain_unregister(
&iosf_mbi_pmic_bus_access_notifier, nb);
mutex_unlock(&iosf_mbi_punit_mutex);
return ret;
}
EXPORT_SYMBOL(iosf_mbi_unregister_pmic_bus_access_notifier);
int iosf_mbi_call_pmic_bus_access_notifier_chain(unsigned long val, void *v)
{
return blocking_notifier_call_chain(
&iosf_mbi_pmic_bus_access_notifier, val, v);
}
EXPORT_SYMBOL(iosf_mbi_call_pmic_bus_access_notifier_chain);
#ifdef CONFIG_IOSF_MBI_DEBUG #ifdef CONFIG_IOSF_MBI_DEBUG
static u32 dbg_mdr; static u32 dbg_mdr;
static u32 dbg_mcr; static u32 dbg_mcr;
......
...@@ -20,6 +20,7 @@ config DRM_I915 ...@@ -20,6 +20,7 @@ config DRM_I915
select ACPI_VIDEO if ACPI select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI select ACPI_BUTTON if ACPI
select SYNC_FILE select SYNC_FILE
select IOSF_MBI
help help
Choose this option if you have a system that has "Intel Graphics Choose this option if you have a system that has "Intel Graphics
Media Accelerator" or "HD Graphics" integrated graphics, Media Accelerator" or "HD Graphics" integrated graphics,
......
...@@ -105,8 +105,8 @@ i915-y += dvo_ch7017.o \ ...@@ -105,8 +105,8 @@ i915-y += dvo_ch7017.o \
intel_dp.o \ intel_dp.o \
intel_dsi.o \ intel_dsi.o \
intel_dsi_dcs_backlight.o \ intel_dsi_dcs_backlight.o \
intel_dsi_panel_vbt.o \
intel_dsi_pll.o \ intel_dsi_pll.o \
intel_dsi_vbt.o \
intel_dvo.o \ intel_dvo.o \
intel_hdmi.o \ intel_hdmi.o \
intel_i2c.o \ intel_i2c.o \
......
...@@ -160,7 +160,6 @@ struct intel_vgpu { ...@@ -160,7 +160,6 @@ struct intel_vgpu {
atomic_t running_workload_num; atomic_t running_workload_num;
DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES); DECLARE_BITMAP(tlb_handle_pending, I915_NUM_ENGINES);
struct i915_gem_context *shadow_ctx; struct i915_gem_context *shadow_ctx;
struct notifier_block shadow_ctx_notifier_block;
#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT) #if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
struct { struct {
...@@ -231,6 +230,7 @@ struct intel_gvt { ...@@ -231,6 +230,7 @@ struct intel_gvt {
struct intel_gvt_gtt gtt; struct intel_gvt_gtt gtt;
struct intel_gvt_opregion opregion; struct intel_gvt_opregion opregion;
struct intel_gvt_workload_scheduler scheduler; struct intel_gvt_workload_scheduler scheduler;
struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS); DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
struct intel_vgpu_type *types; struct intel_vgpu_type *types;
unsigned int num_types; unsigned int num_types;
......
...@@ -130,12 +130,10 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) ...@@ -130,12 +130,10 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
static int shadow_context_status_change(struct notifier_block *nb, static int shadow_context_status_change(struct notifier_block *nb,
unsigned long action, void *data) unsigned long action, void *data)
{ {
struct intel_vgpu *vgpu = container_of(nb, struct drm_i915_gem_request *req = (struct drm_i915_gem_request *)data;
struct intel_vgpu, shadow_ctx_notifier_block); struct intel_gvt *gvt = container_of(nb, struct intel_gvt,
struct drm_i915_gem_request *req = shadow_ctx_notifier_block[req->engine->id]);
(struct drm_i915_gem_request *)data; struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
struct intel_gvt_workload_scheduler *scheduler =
&vgpu->gvt->scheduler;
struct intel_vgpu_workload *workload = struct intel_vgpu_workload *workload =
scheduler->current_workload[req->engine->id]; scheduler->current_workload[req->engine->id];
...@@ -214,7 +212,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) ...@@ -214,7 +212,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
workload->status = ret; workload->status = ret;
if (!IS_ERR_OR_NULL(rq)) if (!IS_ERR_OR_NULL(rq))
i915_add_request_no_flush(rq); i915_add_request(rq);
mutex_unlock(&dev_priv->drm.struct_mutex); mutex_unlock(&dev_priv->drm.struct_mutex);
return ret; return ret;
} }
...@@ -493,15 +491,16 @@ void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu) ...@@ -493,15 +491,16 @@ void intel_gvt_wait_vgpu_idle(struct intel_vgpu *vgpu)
void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt) void intel_gvt_clean_workload_scheduler(struct intel_gvt *gvt)
{ {
struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
int i; struct intel_engine_cs *engine;
enum intel_engine_id i;
gvt_dbg_core("clean workload scheduler\n"); gvt_dbg_core("clean workload scheduler\n");
for (i = 0; i < I915_NUM_ENGINES; i++) { for_each_engine(engine, gvt->dev_priv, i) {
if (scheduler->thread[i]) { atomic_notifier_chain_unregister(
kthread_stop(scheduler->thread[i]); &engine->context_status_notifier,
scheduler->thread[i] = NULL; &gvt->shadow_ctx_notifier_block[i]);
} kthread_stop(scheduler->thread[i]);
} }
} }
...@@ -509,18 +508,15 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt) ...@@ -509,18 +508,15 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
{ {
struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
struct workload_thread_param *param = NULL; struct workload_thread_param *param = NULL;
struct intel_engine_cs *engine;
enum intel_engine_id i;
int ret; int ret;
int i;
gvt_dbg_core("init workload scheduler\n"); gvt_dbg_core("init workload scheduler\n");
init_waitqueue_head(&scheduler->workload_complete_wq); init_waitqueue_head(&scheduler->workload_complete_wq);
for (i = 0; i < I915_NUM_ENGINES; i++) { for_each_engine(engine, gvt->dev_priv, i) {
/* check ring mask at init time */
if (!HAS_ENGINE(gvt->dev_priv, i))
continue;
init_waitqueue_head(&scheduler->waitq[i]); init_waitqueue_head(&scheduler->waitq[i]);
param = kzalloc(sizeof(*param), GFP_KERNEL); param = kzalloc(sizeof(*param), GFP_KERNEL);
...@@ -539,6 +535,11 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt) ...@@ -539,6 +535,11 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
ret = PTR_ERR(scheduler->thread[i]); ret = PTR_ERR(scheduler->thread[i]);
goto err; goto err;
} }
gvt->shadow_ctx_notifier_block[i].notifier_call =
shadow_context_status_change;
atomic_notifier_chain_register(&engine->context_status_notifier,
&gvt->shadow_ctx_notifier_block[i]);
} }
return 0; return 0;
err: err:
...@@ -550,9 +551,6 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt) ...@@ -550,9 +551,6 @@ int intel_gvt_init_workload_scheduler(struct intel_gvt *gvt)
void intel_vgpu_clean_gvt_context(struct intel_vgpu *vgpu) void intel_vgpu_clean_gvt_context(struct intel_vgpu *vgpu)
{ {
atomic_notifier_chain_unregister(&vgpu->shadow_ctx->status_notifier,
&vgpu->shadow_ctx_notifier_block);
i915_gem_context_put_unlocked(vgpu->shadow_ctx); i915_gem_context_put_unlocked(vgpu->shadow_ctx);
} }
...@@ -567,10 +565,5 @@ int intel_vgpu_init_gvt_context(struct intel_vgpu *vgpu) ...@@ -567,10 +565,5 @@ int intel_vgpu_init_gvt_context(struct intel_vgpu *vgpu)
vgpu->shadow_ctx->engine[RCS].initialised = true; vgpu->shadow_ctx->engine[RCS].initialised = true;
vgpu->shadow_ctx_notifier_block.notifier_call =
shadow_context_status_change;
atomic_notifier_chain_register(&vgpu->shadow_ctx->status_notifier,
&vgpu->shadow_ctx_notifier_block);
return 0; return 0;
} }
...@@ -1279,11 +1279,17 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, ...@@ -1279,11 +1279,17 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
* space. Parsing should be faster in some cases this way. * space. Parsing should be faster in some cases this way.
*/ */
batch_end = cmd + (batch_len / sizeof(*batch_end)); batch_end = cmd + (batch_len / sizeof(*batch_end));
while (cmd < batch_end) { do {
u32 length; u32 length;
if (*cmd == MI_BATCH_BUFFER_END) if (*cmd == MI_BATCH_BUFFER_END) {
if (needs_clflush_after) {
void *ptr = ptr_mask_bits(shadow_batch_obj->mm.mapping);
drm_clflush_virt_range(ptr,
(void *)(cmd + 1) - ptr);
}
break; break;
}
desc = find_cmd(engine, *cmd, desc, &default_desc); desc = find_cmd(engine, *cmd, desc, &default_desc);
if (!desc) { if (!desc) {
...@@ -1323,17 +1329,14 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, ...@@ -1323,17 +1329,14 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine,
} }
cmd += length; cmd += length;
} if (cmd >= batch_end) {
DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
if (cmd >= batch_end) { ret = -EINVAL;
DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n"); break;
ret = -EINVAL; }
} } while (1);
if (ret == 0 && needs_clflush_after)
drm_clflush_virt_range(shadow_batch_obj->mm.mapping, batch_len);
i915_gem_object_unpin_map(shadow_batch_obj); i915_gem_object_unpin_map(shadow_batch_obj);
return ret; return ret;
} }
......
此差异已折叠。
...@@ -567,9 +567,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -567,9 +567,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (i915_inject_load_failure()) if (i915_inject_load_failure())
return -ENODEV; return -ENODEV;
ret = intel_bios_init(dev_priv); intel_bios_init(dev_priv);
if (ret)
DRM_INFO("failed to find VBIOS tables\n");
/* If we have > 1 VGA cards, then we need to arbitrate access /* If we have > 1 VGA cards, then we need to arbitrate access
* to the common VGA resources. * to the common VGA resources.
...@@ -607,8 +605,7 @@ static int i915_load_modeset_init(struct drm_device *dev) ...@@ -607,8 +605,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_uc_init_fw(dev_priv);
intel_guc_init(dev_priv);
ret = i915_gem_init(dev_priv); ret = i915_gem_init(dev_priv);
if (ret) if (ret)
...@@ -827,7 +824,6 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv, ...@@ -827,7 +824,6 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
spin_lock_init(&dev_priv->mm.object_stat_lock); spin_lock_init(&dev_priv->mm.object_stat_lock);
spin_lock_init(&dev_priv->mmio_flip_lock); spin_lock_init(&dev_priv->mmio_flip_lock);
spin_lock_init(&dev_priv->wm.dsparb_lock);
mutex_init(&dev_priv->sb_lock); mutex_init(&dev_priv->sb_lock);
mutex_init(&dev_priv->modeset_restore_lock); mutex_init(&dev_priv->modeset_restore_lock);
mutex_init(&dev_priv->av_mutex); mutex_init(&dev_priv->av_mutex);
...@@ -992,6 +988,8 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv) ...@@ -992,6 +988,8 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
i915.semaphores = intel_sanitize_semaphores(dev_priv, i915.semaphores); i915.semaphores = intel_sanitize_semaphores(dev_priv, i915.semaphores);
DRM_DEBUG_DRIVER("use GPU semaphores? %s\n", yesno(i915.semaphores)); DRM_DEBUG_DRIVER("use GPU semaphores? %s\n", yesno(i915.semaphores));
intel_uc_sanitize_options(dev_priv);
} }
/** /**
...@@ -1423,17 +1421,14 @@ static void i915_driver_lastclose(struct drm_device *dev) ...@@ -1423,17 +1421,14 @@ static void i915_driver_lastclose(struct drm_device *dev)
vga_switcheroo_process_delayed_switch(); vga_switcheroo_process_delayed_switch();
} }
static void i915_driver_preclose(struct drm_device *dev, struct drm_file *file) static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
{ {
struct drm_i915_file_private *file_priv = file->driver_priv;
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_context_close(dev, file); i915_gem_context_close(dev, file);
i915_gem_release(dev, file); i915_gem_release(dev, file);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
}
static void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
kfree(file_priv); kfree(file_priv);
} }
...@@ -1512,7 +1507,7 @@ static int i915_drm_suspend(struct drm_device *dev) ...@@ -1512,7 +1507,7 @@ static int i915_drm_suspend(struct drm_device *dev)
opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold; opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
intel_opregion_notify_adapter(dev_priv, opregion_target_state); intel_opregion_notify_adapter(dev_priv, opregion_target_state);
intel_uncore_forcewake_reset(dev_priv, false); intel_uncore_suspend(dev_priv);
intel_opregion_unregister(dev_priv); intel_opregion_unregister(dev_priv);
intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true); intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
...@@ -1757,7 +1752,7 @@ static int i915_drm_resume_early(struct drm_device *dev) ...@@ -1757,7 +1752,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
DRM_ERROR("Resume prepare failed: %d, continuing anyway\n", DRM_ERROR("Resume prepare failed: %d, continuing anyway\n",
ret); ret);
intel_uncore_early_sanitize(dev_priv, true); intel_uncore_resume_early(dev_priv);
if (IS_GEN9_LP(dev_priv)) { if (IS_GEN9_LP(dev_priv)) {
if (!dev_priv->suspended_to_idle) if (!dev_priv->suspended_to_idle)
...@@ -1820,12 +1815,15 @@ void i915_reset(struct drm_i915_private *dev_priv) ...@@ -1820,12 +1815,15 @@ void i915_reset(struct drm_i915_private *dev_priv)
int ret; int ret;
lockdep_assert_held(&dev_priv->drm.struct_mutex); lockdep_assert_held(&dev_priv->drm.struct_mutex);
GEM_BUG_ON(!test_bit(I915_RESET_BACKOFF, &error->flags));
if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags)) if (!test_bit(I915_RESET_HANDOFF, &error->flags))
return; return;
/* Clear any previous failed attempts at recovery. Time to try again. */ /* Clear any previous failed attempts at recovery. Time to try again. */
__clear_bit(I915_WEDGED, &error->flags); if (!i915_gem_unset_wedged(dev_priv))
goto wakeup;
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");
...@@ -1871,15 +1869,18 @@ void i915_reset(struct drm_i915_private *dev_priv) ...@@ -1871,15 +1869,18 @@ void i915_reset(struct drm_i915_private *dev_priv)
i915_queue_hangcheck(dev_priv); i915_queue_hangcheck(dev_priv);
wakeup: finish:
i915_gem_reset_finish(dev_priv); i915_gem_reset_finish(dev_priv);
enable_irq(dev_priv->drm.irq); enable_irq(dev_priv->drm.irq);
wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS);
wakeup:
clear_bit(I915_RESET_HANDOFF, &error->flags);
wake_up_bit(&error->flags, I915_RESET_HANDOFF);
return; return;
error: error:
i915_gem_set_wedged(dev_priv); i915_gem_set_wedged(dev_priv);
goto wakeup; goto finish;
} }
static int i915_pm_suspend(struct device *kdev) static int i915_pm_suspend(struct device *kdev)
...@@ -2402,7 +2403,7 @@ static int intel_runtime_suspend(struct device *kdev) ...@@ -2402,7 +2403,7 @@ static int intel_runtime_suspend(struct device *kdev)
return ret; return ret;
} }
intel_uncore_forcewake_reset(dev_priv, false); intel_uncore_suspend(dev_priv);
enable_rpm_wakeref_asserts(dev_priv); enable_rpm_wakeref_asserts(dev_priv);
WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count)); WARN_ON_ONCE(atomic_read(&dev_priv->pm.wakeref_count));
...@@ -2638,7 +2639,6 @@ static struct drm_driver driver = { ...@@ -2638,7 +2639,6 @@ static struct drm_driver driver = {
.release = i915_driver_release, .release = i915_driver_release,
.open = i915_driver_open, .open = i915_driver_open,
.lastclose = i915_driver_lastclose, .lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.postclose = i915_driver_postclose, .postclose = i915_driver_postclose,
.set_busid = drm_pci_set_busid, .set_busid = drm_pci_set_busid,
......
...@@ -79,8 +79,8 @@ ...@@ -79,8 +79,8 @@
#define DRIVER_NAME "i915" #define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics" #define DRIVER_DESC "Intel Graphics"
#define DRIVER_DATE "20170306" #define DRIVER_DATE "20170320"
#define DRIVER_TIMESTAMP 1488785683 #define DRIVER_TIMESTAMP 1489994464
#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 :( */
...@@ -489,10 +489,8 @@ struct i915_hotplug { ...@@ -489,10 +489,8 @@ struct i915_hotplug {
&(dev)->mode_config.encoder_list, \ &(dev)->mode_config.encoder_list, \
base.head) base.head)
#define for_each_intel_connector(dev, intel_connector) \ #define for_each_intel_connector_iter(intel_connector, iter) \
list_for_each_entry(intel_connector, \ while ((intel_connector = to_intel_connector(drm_connector_list_iter_next(iter))))
&(dev)->mode_config.connector_list, \
base.head)
#define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
...@@ -764,6 +762,7 @@ struct intel_uncore { ...@@ -764,6 +762,7 @@ struct intel_uncore {
const struct intel_forcewake_range *fw_domains_table; const struct intel_forcewake_range *fw_domains_table;
unsigned int fw_domains_table_entries; unsigned int fw_domains_table_entries;
struct notifier_block pmic_bus_access_nb;
struct intel_uncore_funcs funcs; struct intel_uncore_funcs funcs;
unsigned fifo_count; unsigned fifo_count;
...@@ -1324,7 +1323,7 @@ struct vlv_s0ix_state { ...@@ -1324,7 +1323,7 @@ struct vlv_s0ix_state {
}; };
struct intel_rps_ei { struct intel_rps_ei {
u32 cz_clock; ktime_t ktime;
u32 render_c0; u32 render_c0;
u32 media_c0; u32 media_c0;
}; };
...@@ -1339,7 +1338,7 @@ struct intel_gen6_power_mgmt { ...@@ -1339,7 +1338,7 @@ struct intel_gen6_power_mgmt {
u32 pm_iir; u32 pm_iir;
/* PM interrupt bits that should never be masked */ /* PM interrupt bits that should never be masked */
u32 pm_intr_keep; u32 pm_intrmsk_mbz;
/* Frequencies are stored in potentially platform dependent multiples. /* Frequencies are stored in potentially platform dependent multiples.
* In other words, *_freq needs to be multiplied by X to be interesting. * In other words, *_freq needs to be multiplied by X to be interesting.
...@@ -1378,7 +1377,7 @@ struct intel_gen6_power_mgmt { ...@@ -1378,7 +1377,7 @@ struct intel_gen6_power_mgmt {
unsigned boosts; unsigned boosts;
/* manual wa residency calculations */ /* manual wa residency calculations */
struct intel_rps_ei up_ei, down_ei; struct intel_rps_ei ei;
/* /*
* Protects RPS/RC6 register access and PCU communication. * Protects RPS/RC6 register access and PCU communication.
...@@ -1596,8 +1595,33 @@ struct i915_gpu_error { ...@@ -1596,8 +1595,33 @@ struct i915_gpu_error {
*/ */
unsigned long reset_count; unsigned long reset_count;
/**
* flags: Control various stages of the GPU reset
*
* #I915_RESET_BACKOFF - When we start a reset, we want to stop any
* other users acquiring the struct_mutex. To do this we set the
* #I915_RESET_BACKOFF bit in the error flags when we detect a reset
* and then check for that bit before acquiring the struct_mutex (in
* i915_mutex_lock_interruptible()?). I915_RESET_BACKOFF serves a
* secondary role in preventing two concurrent global reset attempts.
*
* #I915_RESET_HANDOFF - To perform the actual GPU reset, we need the
* struct_mutex. We try to acquire the struct_mutex in the reset worker,
* but it may be held by some long running waiter (that we cannot
* interrupt without causing trouble). Once we are ready to do the GPU
* reset, we set the I915_RESET_HANDOFF bit and wakeup any waiters. If
* they already hold the struct_mutex and want to participate they can
* inspect the bit and do the reset directly, otherwise the worker
* waits for the struct_mutex.
*
* #I915_WEDGED - If reset fails and we can no longer use the GPU,
* we set the #I915_WEDGED bit. Prior to command submission, e.g.
* i915_gem_request_alloc(), this bit is checked and the sequence
* aborted (with -EIO reported to userspace) if set.
*/
unsigned long flags; unsigned long flags;
#define I915_RESET_IN_PROGRESS 0 #define I915_RESET_BACKOFF 0
#define I915_RESET_HANDOFF 1
#define I915_WEDGED (BITS_PER_LONG - 1) #define I915_WEDGED (BITS_PER_LONG - 1)
/** /**
...@@ -2376,9 +2400,6 @@ struct drm_i915_private { ...@@ -2376,9 +2400,6 @@ struct drm_i915_private {
} sagv_status; } sagv_status;
struct { struct {
/* protects DSPARB registers on pre-g4x/vlv/chv */
spinlock_t dsparb_lock;
/* /*
* Raw watermark latency values: * Raw watermark latency values:
* in 0.1us units for WM0, * in 0.1us units for WM0,
...@@ -2545,6 +2566,11 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) ...@@ -2545,6 +2566,11 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
return container_of(guc, struct drm_i915_private, guc); return container_of(guc, struct drm_i915_private, guc);
} }
static inline struct drm_i915_private *huc_to_i915(struct intel_huc *huc)
{
return container_of(huc, struct drm_i915_private, huc);
}
/* Simple iterator over all initialised engines */ /* Simple iterator over all initialised engines */
#define for_each_engine(engine__, dev_priv__, id__) \ #define for_each_engine(engine__, dev_priv__, id__) \
for ((id__) = 0; \ for ((id__) = 0; \
...@@ -3057,14 +3083,12 @@ int intel_irq_install(struct drm_i915_private *dev_priv); ...@@ -3057,14 +3083,12 @@ int intel_irq_install(struct drm_i915_private *dev_priv);
void intel_irq_uninstall(struct drm_i915_private *dev_priv); void intel_irq_uninstall(struct drm_i915_private *dev_priv);
extern void intel_uncore_sanitize(struct drm_i915_private *dev_priv); extern void intel_uncore_sanitize(struct drm_i915_private *dev_priv);
extern void intel_uncore_early_sanitize(struct drm_i915_private *dev_priv,
bool restore_forcewake);
extern void intel_uncore_init(struct drm_i915_private *dev_priv); extern void intel_uncore_init(struct drm_i915_private *dev_priv);
extern bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv); extern bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv);
extern bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv); extern bool intel_uncore_arm_unclaimed_mmio_detection(struct drm_i915_private *dev_priv);
extern void intel_uncore_fini(struct drm_i915_private *dev_priv); extern void intel_uncore_fini(struct drm_i915_private *dev_priv);
extern void intel_uncore_forcewake_reset(struct drm_i915_private *dev_priv, extern void intel_uncore_suspend(struct drm_i915_private *dev_priv);
bool restore); extern void intel_uncore_resume_early(struct drm_i915_private *dev_priv);
const char *intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id); const char *intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id);
void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv, void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
enum forcewake_domains domains); enum forcewake_domains domains);
...@@ -3356,9 +3380,9 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, ...@@ -3356,9 +3380,9 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
unsigned int *needs_clflush); unsigned int *needs_clflush);
int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj, int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
unsigned int *needs_clflush); unsigned int *needs_clflush);
#define CLFLUSH_BEFORE 0x1 #define CLFLUSH_BEFORE BIT(0)
#define CLFLUSH_AFTER 0x2 #define CLFLUSH_AFTER BIT(1)
#define CLFLUSH_FLAGS (CLFLUSH_BEFORE | CLFLUSH_AFTER) #define CLFLUSH_FLAGS (CLFLUSH_BEFORE | CLFLUSH_AFTER)
static inline void static inline void
i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj) i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj)
...@@ -3388,9 +3412,14 @@ i915_gem_find_active_request(struct intel_engine_cs *engine); ...@@ -3388,9 +3412,14 @@ i915_gem_find_active_request(struct intel_engine_cs *engine);
void i915_gem_retire_requests(struct drm_i915_private *dev_priv); void i915_gem_retire_requests(struct drm_i915_private *dev_priv);
static inline bool i915_reset_in_progress(struct i915_gpu_error *error) static inline bool i915_reset_backoff(struct i915_gpu_error *error)
{
return unlikely(test_bit(I915_RESET_BACKOFF, &error->flags));
}
static inline bool i915_reset_handoff(struct i915_gpu_error *error)
{ {
return unlikely(test_bit(I915_RESET_IN_PROGRESS, &error->flags)); return unlikely(test_bit(I915_RESET_HANDOFF, &error->flags));
} }
static inline bool i915_terminally_wedged(struct i915_gpu_error *error) static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
...@@ -3398,9 +3427,9 @@ static inline bool i915_terminally_wedged(struct i915_gpu_error *error) ...@@ -3398,9 +3427,9 @@ static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
return unlikely(test_bit(I915_WEDGED, &error->flags)); return unlikely(test_bit(I915_WEDGED, &error->flags));
} }
static inline bool i915_reset_in_progress_or_wedged(struct i915_gpu_error *error) static inline bool i915_reset_backoff_or_wedged(struct i915_gpu_error *error)
{ {
return i915_reset_in_progress(error) | i915_terminally_wedged(error); return i915_reset_backoff(error) | i915_terminally_wedged(error);
} }
static inline u32 i915_reset_count(struct i915_gpu_error *error) static inline u32 i915_reset_count(struct i915_gpu_error *error)
...@@ -3412,6 +3441,7 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv); ...@@ -3412,6 +3441,7 @@ int i915_gem_reset_prepare(struct drm_i915_private *dev_priv);
void i915_gem_reset(struct drm_i915_private *dev_priv); void i915_gem_reset(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);
bool i915_gem_unset_wedged(struct drm_i915_private *dev_priv);
void i915_gem_init_mmio(struct drm_i915_private *i915); void i915_gem_init_mmio(struct drm_i915_private *i915);
int __must_check i915_gem_init(struct drm_i915_private *dev_priv); int __must_check i915_gem_init(struct drm_i915_private *dev_priv);
...@@ -3717,7 +3747,7 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter) ...@@ -3717,7 +3747,7 @@ static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
extern void intel_i2c_reset(struct drm_i915_private *dev_priv); extern void intel_i2c_reset(struct drm_i915_private *dev_priv);
/* intel_bios.c */ /* intel_bios.c */
int intel_bios_init(struct drm_i915_private *dev_priv); void intel_bios_init(struct drm_i915_private *dev_priv);
bool intel_bios_is_valid_vbt(const void *buf, size_t size); bool intel_bios_is_valid_vbt(const void *buf, size_t size);
bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin); bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin);
...@@ -3880,6 +3910,8 @@ void vlv_phy_reset_lanes(struct intel_encoder *encoder); ...@@ -3880,6 +3910,8 @@ void vlv_phy_reset_lanes(struct intel_encoder *encoder);
int intel_gpu_freq(struct drm_i915_private *dev_priv, int val); int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
int intel_freq_opcode(struct drm_i915_private *dev_priv, int val); int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
u64 intel_rc6_residency_us(struct drm_i915_private *dev_priv,
const i915_reg_t reg);
#define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true) #define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true)
#define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true) #define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true)
...@@ -4087,7 +4119,6 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req) ...@@ -4087,7 +4119,6 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
if (engine->irq_seqno_barrier && if (engine->irq_seqno_barrier &&
test_and_clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted)) { test_and_clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted)) {
struct intel_breadcrumbs *b = &engine->breadcrumbs; struct intel_breadcrumbs *b = &engine->breadcrumbs;
unsigned long flags;
/* The ordering of irq_posted versus applying the barrier /* The ordering of irq_posted versus applying the barrier
* is crucial. The clearing of the current irq_posted must * is crucial. The clearing of the current irq_posted must
...@@ -4109,7 +4140,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req) ...@@ -4109,7 +4140,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
* the seqno before we believe it coherent since they see * the seqno before we believe it coherent since they see
* irq_posted == false but we are still running). * irq_posted == false but we are still running).
*/ */
spin_lock_irqsave(&b->irq_lock, flags); spin_lock_irq(&b->irq_lock);
if (b->irq_wait && b->irq_wait->tsk != current) if (b->irq_wait && b->irq_wait->tsk != current)
/* Note that if the bottom-half is changed as we /* Note that if the bottom-half is changed as we
* are sending the wake-up, the new bottom-half will * are sending the wake-up, the new bottom-half will
...@@ -4118,7 +4149,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req) ...@@ -4118,7 +4149,7 @@ __i915_request_irq_complete(const struct drm_i915_gem_request *req)
* ourself. * ourself.
*/ */
wake_up_process(b->irq_wait->tsk); wake_up_process(b->irq_wait->tsk);
spin_unlock_irqrestore(&b->irq_lock, flags); spin_unlock_irq(&b->irq_lock);
if (__i915_gem_request_completed(req, seqno)) if (__i915_gem_request_completed(req, seqno))
return true; return true;
......
...@@ -103,16 +103,13 @@ i915_gem_wait_for_error(struct i915_gpu_error *error) ...@@ -103,16 +103,13 @@ i915_gem_wait_for_error(struct i915_gpu_error *error)
might_sleep(); might_sleep();
if (!i915_reset_in_progress(error))
return 0;
/* /*
* Only wait 10 seconds for the gpu reset to complete to avoid hanging * Only wait 10 seconds for the gpu reset to complete to avoid hanging
* userspace. If it takes that long something really bad is going on and * userspace. If it takes that long something really bad is going on and
* we should simply try to bail out and fail as gracefully as possible. * we should simply try to bail out and fail as gracefully as possible.
*/ */
ret = wait_event_interruptible_timeout(error->reset_queue, ret = wait_event_interruptible_timeout(error->reset_queue,
!i915_reset_in_progress(error), !i915_reset_backoff(error),
I915_RESET_TIMEOUT); I915_RESET_TIMEOUT);
if (ret == 0) { if (ret == 0) {
DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); DRM_ERROR("Timed out waiting for the gpu reset to complete\n");
...@@ -462,11 +459,16 @@ i915_gem_object_wait_reservation(struct reservation_object *resv, ...@@ -462,11 +459,16 @@ i915_gem_object_wait_reservation(struct reservation_object *resv,
dma_fence_put(excl); dma_fence_put(excl);
/* Oportunistically prune the fences iff we know they have *all* been
* signaled and that the reservation object has not been changed (i.e.
* no new fences have been added).
*/
if (prune_fences && !__read_seqcount_retry(&resv->seq, seq)) { if (prune_fences && !__read_seqcount_retry(&resv->seq, seq)) {
reservation_object_lock(resv, NULL); if (reservation_object_trylock(resv)) {
if (!__read_seqcount_retry(&resv->seq, seq)) if (!__read_seqcount_retry(&resv->seq, seq))
reservation_object_add_excl_fence(resv, NULL); reservation_object_add_excl_fence(resv, NULL);
reservation_object_unlock(resv); reservation_object_unlock(resv);
}
} }
return timeout; return timeout;
...@@ -783,6 +785,15 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, ...@@ -783,6 +785,15 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
if (ret) if (ret)
return ret; return ret;
if (i915_gem_object_is_coherent(obj) ||
!static_cpu_has(X86_FEATURE_CLFLUSH)) {
ret = i915_gem_object_set_to_cpu_domain(obj, false);
if (ret)
goto err_unpin;
else
goto out;
}
i915_gem_object_flush_gtt_write_domain(obj); i915_gem_object_flush_gtt_write_domain(obj);
/* If we're not in the cpu read domain, set ourself into the gtt /* If we're not in the cpu read domain, set ourself into the gtt
...@@ -791,16 +802,9 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj, ...@@ -791,16 +802,9 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
* anyway again before the next pread happens. * anyway again before the next pread happens.
*/ */
if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
*needs_clflush = !i915_gem_object_is_coherent(obj); *needs_clflush = CLFLUSH_BEFORE;
if (*needs_clflush && !static_cpu_has(X86_FEATURE_CLFLUSH)) {
ret = i915_gem_object_set_to_cpu_domain(obj, false);
if (ret)
goto err_unpin;
*needs_clflush = 0;
}
out:
/* return with the pages pinned */ /* return with the pages pinned */
return 0; return 0;
...@@ -833,6 +837,15 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj, ...@@ -833,6 +837,15 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
if (ret) if (ret)
return ret; return ret;
if (i915_gem_object_is_coherent(obj) ||
!static_cpu_has(X86_FEATURE_CLFLUSH)) {
ret = i915_gem_object_set_to_cpu_domain(obj, true);
if (ret)
goto err_unpin;
else
goto out;
}
i915_gem_object_flush_gtt_write_domain(obj); i915_gem_object_flush_gtt_write_domain(obj);
/* If we're not in the cpu write domain, set ourself into the /* If we're not in the cpu write domain, set ourself into the
...@@ -841,25 +854,15 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj, ...@@ -841,25 +854,15 @@ int i915_gem_obj_prepare_shmem_write(struct drm_i915_gem_object *obj,
* right away and we therefore have to clflush anyway. * right away and we therefore have to clflush anyway.
*/ */
if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
*needs_clflush |= cpu_write_needs_clflush(obj) << 1; *needs_clflush |= CLFLUSH_AFTER;
/* Same trick applies to invalidate partially written cachelines read /* Same trick applies to invalidate partially written cachelines read
* before writing. * before writing.
*/ */
if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU))
*needs_clflush |= !i915_gem_object_is_coherent(obj); *needs_clflush |= CLFLUSH_BEFORE;
if (*needs_clflush && !static_cpu_has(X86_FEATURE_CLFLUSH)) {
ret = i915_gem_object_set_to_cpu_domain(obj, true);
if (ret)
goto err_unpin;
*needs_clflush = 0;
}
if ((*needs_clflush & CLFLUSH_AFTER) == 0)
obj->cache_dirty = true;
out:
intel_fb_obj_invalidate(obj, ORIGIN_CPU); intel_fb_obj_invalidate(obj, ORIGIN_CPU);
obj->mm.dirty = true; obj->mm.dirty = true;
/* return with the pages pinned */ /* return with the pages pinned */
...@@ -1452,6 +1455,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, ...@@ -1452,6 +1455,12 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
trace_i915_gem_object_pwrite(obj, args->offset, args->size); trace_i915_gem_object_pwrite(obj, args->offset, args->size);
ret = -ENODEV;
if (obj->ops->pwrite)
ret = obj->ops->pwrite(obj, args);
if (ret != -ENODEV)
goto err;
ret = i915_gem_object_wait(obj, ret = i915_gem_object_wait(obj,
I915_WAIT_INTERRUPTIBLE | I915_WAIT_INTERRUPTIBLE |
I915_WAIT_ALL, I915_WAIT_ALL,
...@@ -2130,6 +2139,7 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj) ...@@ -2130,6 +2139,7 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
*/ */
shmem_truncate_range(file_inode(obj->base.filp), 0, (loff_t)-1); shmem_truncate_range(file_inode(obj->base.filp), 0, (loff_t)-1);
obj->mm.madv = __I915_MADV_PURGED; obj->mm.madv = __I915_MADV_PURGED;
obj->mm.pages = ERR_PTR(-EFAULT);
} }
/* Try to discard unwanted pages */ /* Try to discard unwanted pages */
...@@ -2229,7 +2239,9 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, ...@@ -2229,7 +2239,9 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
__i915_gem_object_reset_page_iter(obj); __i915_gem_object_reset_page_iter(obj);
obj->ops->put_pages(obj, pages); if (!IS_ERR(pages))
obj->ops->put_pages(obj, pages);
unlock: unlock:
mutex_unlock(&obj->mm.lock); mutex_unlock(&obj->mm.lock);
} }
...@@ -2449,7 +2461,7 @@ int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj) ...@@ -2449,7 +2461,7 @@ int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
if (err) if (err)
return err; return err;
if (unlikely(!obj->mm.pages)) { if (unlikely(IS_ERR_OR_NULL(obj->mm.pages))) {
err = ____i915_gem_object_get_pages(obj); err = ____i915_gem_object_get_pages(obj);
if (err) if (err)
goto unlock; goto unlock;
...@@ -2527,7 +2539,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, ...@@ -2527,7 +2539,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
pinned = true; pinned = true;
if (!atomic_inc_not_zero(&obj->mm.pages_pin_count)) { if (!atomic_inc_not_zero(&obj->mm.pages_pin_count)) {
if (unlikely(!obj->mm.pages)) { if (unlikely(IS_ERR_OR_NULL(obj->mm.pages))) {
ret = ____i915_gem_object_get_pages(obj); ret = ____i915_gem_object_get_pages(obj);
if (ret) if (ret)
goto err_unlock; goto err_unlock;
...@@ -2575,6 +2587,75 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, ...@@ -2575,6 +2587,75 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
goto out_unlock; goto out_unlock;
} }
static int
i915_gem_object_pwrite_gtt(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_pwrite *arg)
{
struct address_space *mapping = obj->base.filp->f_mapping;
char __user *user_data = u64_to_user_ptr(arg->data_ptr);
u64 remain, offset;
unsigned int pg;
/* Before we instantiate/pin the backing store for our use, we
* can prepopulate the shmemfs filp efficiently using a write into
* the pagecache. We avoid the penalty of instantiating all the
* pages, important if the user is just writing to a few and never
* uses the object on the GPU, and using a direct write into shmemfs
* allows it to avoid the cost of retrieving a page (either swapin
* or clearing-before-use) before it is overwritten.
*/
if (READ_ONCE(obj->mm.pages))
return -ENODEV;
/* Before the pages are instantiated the object is treated as being
* in the CPU domain. The pages will be clflushed as required before
* use, and we can freely write into the pages directly. If userspace
* races pwrite with any other operation; corruption will ensue -
* that is userspace's prerogative!
*/
remain = arg->size;
offset = arg->offset;
pg = offset_in_page(offset);
do {
unsigned int len, unwritten;
struct page *page;
void *data, *vaddr;
int err;
len = PAGE_SIZE - pg;
if (len > remain)
len = remain;
err = pagecache_write_begin(obj->base.filp, mapping,
offset, len, 0,
&page, &data);
if (err < 0)
return err;
vaddr = kmap(page);
unwritten = copy_from_user(vaddr + pg, user_data, len);
kunmap(page);
err = pagecache_write_end(obj->base.filp, mapping,
offset, len, len - unwritten,
page, data);
if (err < 0)
return err;
if (unwritten)
return -EFAULT;
remain -= len;
user_data += len;
offset += len;
pg = 0;
} while (remain);
return 0;
}
static bool ban_context(const struct i915_gem_context *ctx) static bool ban_context(const struct i915_gem_context *ctx)
{ {
return (i915_gem_context_is_bannable(ctx) && return (i915_gem_context_is_bannable(ctx) &&
...@@ -2916,6 +2997,65 @@ void i915_gem_set_wedged(struct drm_i915_private *dev_priv) ...@@ -2916,6 +2997,65 @@ void i915_gem_set_wedged(struct drm_i915_private *dev_priv)
mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0); mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0);
} }
bool i915_gem_unset_wedged(struct drm_i915_private *i915)
{
struct i915_gem_timeline *tl;
int i;
lockdep_assert_held(&i915->drm.struct_mutex);
if (!test_bit(I915_WEDGED, &i915->gpu_error.flags))
return true;
/* Before unwedging, make sure that all pending operations
* are flushed and errored out - we may have requests waiting upon
* third party fences. We marked all inflight requests as EIO, and
* every execbuf since returned EIO, for consistency we want all
* the currently pending requests to also be marked as EIO, which
* is done inside our nop_submit_request - and so we must wait.
*
* No more can be submitted until we reset the wedged bit.
*/
list_for_each_entry(tl, &i915->gt.timelines, link) {
for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
struct drm_i915_gem_request *rq;
rq = i915_gem_active_peek(&tl->engine[i].last_request,
&i915->drm.struct_mutex);
if (!rq)
continue;
/* We can't use our normal waiter as we want to
* avoid recursively trying to handle the current
* reset. The basic dma_fence_default_wait() installs
* a callback for dma_fence_signal(), which is
* triggered by our nop handler (indirectly, the
* callback enables the signaler thread which is
* woken by the nop_submit_request() advancing the seqno
* and when the seqno passes the fence, the signaler
* then signals the fence waking us up).
*/
if (dma_fence_default_wait(&rq->fence, true,
MAX_SCHEDULE_TIMEOUT) < 0)
return false;
}
}
/* Undo nop_submit_request. We prevent all new i915 requests from
* being queued (by disallowing execbuf whilst wedged) so having
* waited for all active requests above, we know the system is idle
* and do not have to worry about a thread being inside
* engine->submit_request() as we swap over. So unlike installing
* the nop_submit_request on reset, we can do this from normal
* context and do not require stop_machine().
*/
intel_engines_reset_default_submission(i915);
smp_mb__before_atomic(); /* complete takeover before enabling execbuf */
clear_bit(I915_WEDGED, &i915->gpu_error.flags);
return true;
}
static void static void
i915_gem_retire_work_handler(struct work_struct *work) i915_gem_retire_work_handler(struct work_struct *work)
{ {
...@@ -3991,8 +4131,11 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, ...@@ -3991,8 +4131,11 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
static const struct drm_i915_gem_object_ops i915_gem_object_ops = { static const struct drm_i915_gem_object_ops i915_gem_object_ops = {
.flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE |
I915_GEM_OBJECT_IS_SHRINKABLE, I915_GEM_OBJECT_IS_SHRINKABLE,
.get_pages = i915_gem_object_get_pages_gtt, .get_pages = i915_gem_object_get_pages_gtt,
.put_pages = i915_gem_object_put_pages_gtt, .put_pages = i915_gem_object_put_pages_gtt,
.pwrite = i915_gem_object_pwrite_gtt,
}; };
struct drm_i915_gem_object * struct drm_i915_gem_object *
...@@ -4454,7 +4597,7 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) ...@@ -4454,7 +4597,7 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv)
intel_mocs_init_l3cc_table(dev_priv); intel_mocs_init_l3cc_table(dev_priv);
/* We can't enable contexts until all firmware is loaded */ /* We can't enable contexts until all firmware is loaded */
ret = intel_guc_setup(dev_priv); ret = intel_uc_init_hw(dev_priv);
if (ret) if (ret)
goto out; goto out;
...@@ -4810,38 +4953,49 @@ i915_gem_object_create_from_data(struct drm_i915_private *dev_priv, ...@@ -4810,38 +4953,49 @@ i915_gem_object_create_from_data(struct drm_i915_private *dev_priv,
const void *data, size_t size) const void *data, size_t size)
{ {
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
struct sg_table *sg; struct file *file;
size_t bytes; size_t offset;
int ret; int err;
obj = i915_gem_object_create(dev_priv, round_up(size, PAGE_SIZE)); obj = i915_gem_object_create(dev_priv, round_up(size, PAGE_SIZE));
if (IS_ERR(obj)) if (IS_ERR(obj))
return obj; return obj;
ret = i915_gem_object_set_to_cpu_domain(obj, true); GEM_BUG_ON(obj->base.write_domain != I915_GEM_DOMAIN_CPU);
if (ret)
goto fail;
ret = i915_gem_object_pin_pages(obj); file = obj->base.filp;
if (ret) offset = 0;
goto fail; do {
unsigned int len = min_t(typeof(size), size, PAGE_SIZE);
struct page *page;
void *pgdata, *vaddr;
sg = obj->mm.pages; err = pagecache_write_begin(file, file->f_mapping,
bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size); offset, len, 0,
obj->mm.dirty = true; /* Backing store is now out of date */ &page, &pgdata);
i915_gem_object_unpin_pages(obj); if (err < 0)
goto fail;
if (WARN_ON(bytes != size)) { vaddr = kmap(page);
DRM_ERROR("Incomplete copy, wrote %zu of %zu", bytes, size); memcpy(vaddr, data, len);
ret = -EFAULT; kunmap(page);
goto fail;
} err = pagecache_write_end(file, file->f_mapping,
offset, len, len,
page, pgdata);
if (err < 0)
goto fail;
size -= len;
data += len;
offset += len;
} while (size);
return obj; return obj;
fail: fail:
i915_gem_object_put(obj); i915_gem_object_put(obj);
return ERR_PTR(ret); return ERR_PTR(err);
} }
struct scatterlist * struct scatterlist *
......
...@@ -96,8 +96,7 @@ struct drm_i915_gem_object * ...@@ -96,8 +96,7 @@ struct drm_i915_gem_object *
i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
size_t size) size_t size)
{ {
struct drm_i915_gem_object *obj = NULL; struct drm_i915_gem_object *obj;
struct drm_i915_gem_object *tmp;
struct list_head *list; struct list_head *list;
int n, ret; int n, ret;
...@@ -112,31 +111,29 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, ...@@ -112,31 +111,29 @@ i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
n = ARRAY_SIZE(pool->cache_list) - 1; n = ARRAY_SIZE(pool->cache_list) - 1;
list = &pool->cache_list[n]; list = &pool->cache_list[n];
list_for_each_entry(tmp, list, batch_pool_link) { list_for_each_entry(obj, list, batch_pool_link) {
/* The batches are strictly LRU ordered */ /* The batches are strictly LRU ordered */
if (i915_gem_object_is_active(tmp)) if (i915_gem_object_is_active(obj)) {
break; if (!reservation_object_test_signaled_rcu(obj->resv,
true))
break;
GEM_BUG_ON(!reservation_object_test_signaled_rcu(tmp->resv, i915_gem_retire_requests(pool->engine->i915);
true)); GEM_BUG_ON(i915_gem_object_is_active(obj));
}
if (tmp->base.size >= size) { GEM_BUG_ON(!reservation_object_test_signaled_rcu(obj->resv,
/* Clear the set of shared fences early */ true));
reservation_object_lock(tmp->resv, NULL);
reservation_object_add_excl_fence(tmp->resv, NULL);
reservation_object_unlock(tmp->resv);
obj = tmp; if (obj->base.size >= size)
break; goto found;
}
} }
if (obj == NULL) { obj = i915_gem_object_create_internal(pool->engine->i915, size);
obj = i915_gem_object_create_internal(pool->engine->i915, size); if (IS_ERR(obj))
if (IS_ERR(obj)) return obj;
return obj;
}
found:
ret = i915_gem_object_pin_pages(obj); ret = i915_gem_object_pin_pages(obj);
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -318,7 +318,6 @@ __create_hw_context(struct drm_i915_private *dev_priv, ...@@ -318,7 +318,6 @@ __create_hw_context(struct drm_i915_private *dev_priv,
ctx->ring_size = 4 * PAGE_SIZE; ctx->ring_size = 4 * PAGE_SIZE;
ctx->desc_template = ctx->desc_template =
default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt); default_desc_template(dev_priv, dev_priv->mm.aliasing_ppgtt);
ATOMIC_INIT_NOTIFIER_HEAD(&ctx->status_notifier);
/* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not /* GuC requires the ring to be placed above GUC_WOPCM_TOP. If GuC is not
* present or not in use we still need a small bias as ring wraparound * present or not in use we still need a small bias as ring wraparound
...@@ -934,7 +933,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv) ...@@ -934,7 +933,7 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
} }
ret = i915_switch_context(req); ret = i915_switch_context(req);
i915_add_request_no_flush(req); i915_add_request(req);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -158,9 +158,6 @@ struct i915_gem_context { ...@@ -158,9 +158,6 @@ struct i915_gem_context {
/** desc_template: invariant fields for the HW context descriptor */ /** desc_template: invariant fields for the HW context descriptor */
u32 desc_template; u32 desc_template;
/** status_notifier: list of callbacks for context-switch changes */
struct atomic_notifier_head status_notifier;
/** guilty_count: How many times this context has caused a GPU hang. */ /** guilty_count: How many times this context has caused a GPU hang. */
unsigned int guilty_count; unsigned int guilty_count;
/** /**
......
...@@ -299,12 +299,12 @@ int i915_gem_evict_for_node(struct i915_address_space *vm, ...@@ -299,12 +299,12 @@ int i915_gem_evict_for_node(struct i915_address_space *vm,
* 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 == node->start) { if (node->start + node->size == target->start) {
if (vma->node.color == node->color) if (node->color == target->color)
continue; continue;
} }
if (vma->node.start == node->start + node->size) { if (node->start == target->start + target->size) {
if (vma->node.color == node->color) if (node->color == target->color)
continue; continue;
} }
} }
......
...@@ -248,7 +248,14 @@ static int fence_update(struct drm_i915_fence_reg *fence, ...@@ -248,7 +248,14 @@ static int fence_update(struct drm_i915_fence_reg *fence,
list_move(&fence->link, &fence->i915->mm.fence_list); list_move(&fence->link, &fence->i915->mm.fence_list);
} }
fence_write(fence, vma); /* We only need to update the register itself if the device is awake.
* If the device is currently powered down, we will defer the write
* to the runtime resume, see i915_gem_restore_fences().
*/
if (intel_runtime_pm_get_if_in_use(fence->i915)) {
fence_write(fence, vma);
intel_runtime_pm_put(fence->i915);
}
if (vma) { if (vma) {
if (fence->vma != vma) { if (fence->vma != vma) {
...@@ -278,8 +285,6 @@ i915_vma_put_fence(struct i915_vma *vma) ...@@ -278,8 +285,6 @@ i915_vma_put_fence(struct i915_vma *vma)
{ {
struct drm_i915_fence_reg *fence = vma->fence; struct drm_i915_fence_reg *fence = vma->fence;
assert_rpm_wakelock_held(vma->vm->i915);
if (!fence) if (!fence)
return 0; return 0;
......
...@@ -56,6 +56,9 @@ struct drm_i915_gem_object_ops { ...@@ -56,6 +56,9 @@ struct drm_i915_gem_object_ops {
struct sg_table *(*get_pages)(struct drm_i915_gem_object *); struct sg_table *(*get_pages)(struct drm_i915_gem_object *);
void (*put_pages)(struct drm_i915_gem_object *, struct sg_table *); void (*put_pages)(struct drm_i915_gem_object *, struct sg_table *);
int (*pwrite)(struct drm_i915_gem_object *,
const struct drm_i915_gem_pwrite *);
int (*dmabuf_export)(struct drm_i915_gem_object *); int (*dmabuf_export)(struct drm_i915_gem_object *);
void (*release)(struct drm_i915_gem_object *); void (*release)(struct drm_i915_gem_object *);
}; };
...@@ -270,12 +273,6 @@ static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj) ...@@ -270,12 +273,6 @@ static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj)
reservation_object_unlock(obj->resv); reservation_object_unlock(obj->resv);
} }
static inline bool
i915_gem_object_is_dead(const struct drm_i915_gem_object *obj)
{
return kref_read(&obj->base.refcount) == 0;
}
static inline bool static inline bool
i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj) i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj)
{ {
......
...@@ -1012,7 +1012,7 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req, ...@@ -1012,7 +1012,7 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req,
static bool __i915_wait_request_check_and_reset(struct drm_i915_gem_request *request) static bool __i915_wait_request_check_and_reset(struct drm_i915_gem_request *request)
{ {
if (likely(!i915_reset_in_progress(&request->i915->gpu_error))) if (likely(!i915_reset_handoff(&request->i915->gpu_error)))
return false; return false;
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
......
...@@ -267,8 +267,6 @@ int i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req, ...@@ -267,8 +267,6 @@ int i915_gem_request_await_dma_fence(struct drm_i915_gem_request *req,
void __i915_add_request(struct drm_i915_gem_request *req, bool flush_caches); void __i915_add_request(struct drm_i915_gem_request *req, bool flush_caches);
#define i915_add_request(req) \ #define i915_add_request(req) \
__i915_add_request(req, true)
#define i915_add_request_no_flush(req) \
__i915_add_request(req, false) __i915_add_request(req, false)
void __i915_gem_request_submit(struct drm_i915_gem_request *request); void __i915_gem_request_submit(struct drm_i915_gem_request *request);
...@@ -348,6 +346,9 @@ static inline bool i915_spin_request(const struct drm_i915_gem_request *request, ...@@ -348,6 +346,9 @@ static inline bool i915_spin_request(const struct drm_i915_gem_request *request,
u32 seqno; u32 seqno;
seqno = i915_gem_request_global_seqno(request); seqno = i915_gem_request_global_seqno(request);
if (!seqno)
return 0;
return (__i915_gem_request_started(request, seqno) && return (__i915_gem_request_started(request, seqno) &&
__i915_spin_request(request, seqno, state, timeout_us)); __i915_spin_request(request, seqno, state, timeout_us));
} }
......
...@@ -266,7 +266,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv) ...@@ -266,7 +266,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv)
I915_SHRINK_ACTIVE); I915_SHRINK_ACTIVE);
intel_runtime_pm_put(dev_priv); intel_runtime_pm_put(dev_priv);
rcu_barrier(); /* wait until our RCU delayed slab frees are completed */ synchronize_rcu(); /* wait for our earlier RCU delayed slab frees */
return freed; return freed;
} }
......
...@@ -66,13 +66,18 @@ static void cancel_userptr(struct work_struct *work) ...@@ -66,13 +66,18 @@ static void cancel_userptr(struct work_struct *work)
{ {
struct i915_mmu_object *mo = container_of(work, typeof(*mo), work); struct i915_mmu_object *mo = container_of(work, typeof(*mo), work);
struct drm_i915_gem_object *obj = mo->obj; struct drm_i915_gem_object *obj = mo->obj;
struct drm_device *dev = obj->base.dev; struct work_struct *active;
/* Cancel any active worker and force us to re-evaluate gup */
mutex_lock(&obj->mm.lock);
active = fetch_and_zero(&obj->userptr.work);
mutex_unlock(&obj->mm.lock);
if (active)
goto out;
i915_gem_object_wait(obj, I915_WAIT_ALL, MAX_SCHEDULE_TIMEOUT, NULL); i915_gem_object_wait(obj, I915_WAIT_ALL, MAX_SCHEDULE_TIMEOUT, NULL);
mutex_lock(&dev->struct_mutex); mutex_lock(&obj->base.dev->struct_mutex);
/* Cancel any active worker and force us to re-evaluate gup */
obj->userptr.work = NULL;
/* We are inside a kthread context and can't be interrupted */ /* We are inside a kthread context and can't be interrupted */
if (i915_gem_object_unbind(obj) == 0) if (i915_gem_object_unbind(obj) == 0)
...@@ -83,8 +88,10 @@ static void cancel_userptr(struct work_struct *work) ...@@ -83,8 +88,10 @@ static void cancel_userptr(struct work_struct *work)
atomic_read(&obj->mm.pages_pin_count), atomic_read(&obj->mm.pages_pin_count),
obj->pin_display); obj->pin_display);
mutex_unlock(&obj->base.dev->struct_mutex);
out:
i915_gem_object_put(obj); i915_gem_object_put(obj);
mutex_unlock(&dev->struct_mutex);
} }
static void add_object(struct i915_mmu_object *mo) static void add_object(struct i915_mmu_object *mo)
...@@ -145,7 +152,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, ...@@ -145,7 +152,8 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
del_object(mo); del_object(mo);
spin_unlock(&mn->lock); spin_unlock(&mn->lock);
flush_workqueue(mn->wq); if (!list_empty(&cancelled))
flush_workqueue(mn->wq);
} }
static const struct mmu_notifier_ops i915_gem_userptr_notifier = { static const struct mmu_notifier_ops i915_gem_userptr_notifier = {
...@@ -541,6 +549,8 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) ...@@ -541,6 +549,8 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
} }
obj->userptr.work = ERR_CAST(pages); obj->userptr.work = ERR_CAST(pages);
if (IS_ERR(pages))
__i915_gem_userptr_set_active(obj, false);
} }
mutex_unlock(&obj->mm.lock); mutex_unlock(&obj->mm.lock);
...@@ -553,8 +563,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) ...@@ -553,8 +563,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
} }
static struct sg_table * static struct sg_table *
__i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj, __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj)
bool *active)
{ {
struct get_pages_work *work; struct get_pages_work *work;
...@@ -591,7 +600,6 @@ __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj, ...@@ -591,7 +600,6 @@ __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj,
INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
schedule_work(&work->work); schedule_work(&work->work);
*active = true;
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
} }
...@@ -599,10 +607,11 @@ static struct sg_table * ...@@ -599,10 +607,11 @@ static struct sg_table *
i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
{ {
const int num_pages = obj->base.size >> PAGE_SHIFT; const int num_pages = obj->base.size >> PAGE_SHIFT;
struct mm_struct *mm = obj->userptr.mm->mm;
struct page **pvec; struct page **pvec;
struct sg_table *pages; struct sg_table *pages;
int pinned, ret;
bool active; bool active;
int pinned;
/* If userspace should engineer that these pages are replaced in /* If userspace should engineer that these pages are replaced in
* the vma between us binding this page into the GTT and completion * the vma between us binding this page into the GTT and completion
...@@ -629,37 +638,39 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) ...@@ -629,37 +638,39 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
return ERR_PTR(-EAGAIN); return ERR_PTR(-EAGAIN);
} }
/* Let the mmu-notifier know that we have begun and need cancellation */
ret = __i915_gem_userptr_set_active(obj, true);
if (ret)
return ERR_PTR(ret);
pvec = NULL; pvec = NULL;
pinned = 0; pinned = 0;
if (obj->userptr.mm->mm == current->mm) {
pvec = drm_malloc_gfp(num_pages, sizeof(struct page *),
GFP_TEMPORARY);
if (pvec == NULL) {
__i915_gem_userptr_set_active(obj, false);
return ERR_PTR(-ENOMEM);
}
pinned = __get_user_pages_fast(obj->userptr.ptr, num_pages, if (mm == current->mm) {
!obj->userptr.read_only, pvec); pvec = drm_malloc_gfp(num_pages, sizeof(struct page *),
GFP_TEMPORARY |
__GFP_NORETRY |
__GFP_NOWARN);
if (pvec) /* defer to worker if malloc fails */
pinned = __get_user_pages_fast(obj->userptr.ptr,
num_pages,
!obj->userptr.read_only,
pvec);
} }
active = false; active = false;
if (pinned < 0) if (pinned < 0) {
pages = ERR_PTR(pinned), pinned = 0; pages = ERR_PTR(pinned);
else if (pinned < num_pages) pinned = 0;
pages = __i915_gem_userptr_get_pages_schedule(obj, &active); } else if (pinned < num_pages) {
else pages = __i915_gem_userptr_get_pages_schedule(obj);
active = pages == ERR_PTR(-EAGAIN);
} else {
pages = __i915_gem_userptr_set_pages(obj, pvec, num_pages); pages = __i915_gem_userptr_set_pages(obj, pvec, num_pages);
if (IS_ERR(pages)) { active = !IS_ERR(pages);
__i915_gem_userptr_set_active(obj, active);
release_pages(pvec, pinned, 0);
} }
if (active)
__i915_gem_userptr_set_active(obj, true);
if (IS_ERR(pages))
release_pages(pvec, pinned, 0);
drm_free_large(pvec); drm_free_large(pvec);
return pages; return pages;
} }
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "i915_drv.h" #include "i915_drv.h"
#include "intel_uc.h" #include "intel_uc.h"
#include <trace/events/dma_fence.h>
/** /**
* DOC: GuC-based command submission * DOC: GuC-based command submission
* *
...@@ -522,8 +524,6 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq) ...@@ -522,8 +524,6 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq)
if (i915_vma_is_map_and_fenceable(rq->ring->vma)) if (i915_vma_is_map_and_fenceable(rq->ring->vma))
POSTING_READ_FW(GUC_STATUS); POSTING_READ_FW(GUC_STATUS);
trace_i915_gem_request_in(rq, 0);
spin_lock_irqsave(&client->wq_lock, flags); spin_lock_irqsave(&client->wq_lock, flags);
guc_wq_item_append(client, rq); guc_wq_item_append(client, rq);
...@@ -542,10 +542,111 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq) ...@@ -542,10 +542,111 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq)
static void i915_guc_submit(struct drm_i915_gem_request *rq) static void i915_guc_submit(struct drm_i915_gem_request *rq)
{ {
i915_gem_request_submit(rq); __i915_gem_request_submit(rq);
__i915_guc_submit(rq); __i915_guc_submit(rq);
} }
static void nested_enable_signaling(struct drm_i915_gem_request *rq)
{
/* If we use dma_fence_enable_sw_signaling() directly, lockdep
* detects an ordering issue between the fence lockclass and the
* global_timeline. This circular dependency can only occur via 2
* different fences (but same fence lockclass), so we use the nesting
* annotation here to prevent the warn, equivalent to the nesting
* inside i915_gem_request_submit() for when we also enable the
* signaler.
*/
if (test_and_set_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT,
&rq->fence.flags))
return;
GEM_BUG_ON(test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags));
trace_dma_fence_enable_signal(&rq->fence);
spin_lock_nested(&rq->lock, SINGLE_DEPTH_NESTING);
intel_engine_enable_signaling(rq);
spin_unlock(&rq->lock);
}
static bool i915_guc_dequeue(struct intel_engine_cs *engine)
{
struct execlist_port *port = engine->execlist_port;
struct drm_i915_gem_request *last = port[0].request;
unsigned long flags;
struct rb_node *rb;
bool submit = false;
/* After execlist_first is updated, the tasklet will be rescheduled.
*
* If we are currently running (inside the tasklet) and a third
* party queues a request and so updates engine->execlist_first under
* the spinlock (which we have elided), it will atomically set the
* TASKLET_SCHED flag causing the us to be re-executed and pick up
* the change in state (the update to TASKLET_SCHED incurs a memory
* barrier making this cross-cpu checking safe).
*/
if (!READ_ONCE(engine->execlist_first))
return false;
spin_lock_irqsave(&engine->timeline->lock, flags);
rb = engine->execlist_first;
while (rb) {
struct drm_i915_gem_request *rq =
rb_entry(rb, typeof(*rq), priotree.node);
if (last && rq->ctx != last->ctx) {
if (port != engine->execlist_port)
break;
i915_gem_request_assign(&port->request, last);
nested_enable_signaling(last);
port++;
}
rb = rb_next(rb);
rb_erase(&rq->priotree.node, &engine->execlist_queue);
RB_CLEAR_NODE(&rq->priotree.node);
rq->priotree.priority = INT_MAX;
trace_i915_gem_request_in(rq, port - engine->execlist_port);
i915_guc_submit(rq);
last = rq;
submit = true;
}
if (submit) {
i915_gem_request_assign(&port->request, last);
nested_enable_signaling(last);
engine->execlist_first = rb;
}
spin_unlock_irqrestore(&engine->timeline->lock, flags);
return submit;
}
static void i915_guc_irq_handler(unsigned long data)
{
struct intel_engine_cs *engine = (struct intel_engine_cs *)data;
struct execlist_port *port = engine->execlist_port;
struct drm_i915_gem_request *rq;
bool submit;
do {
rq = port[0].request;
while (rq && i915_gem_request_completed(rq)) {
trace_i915_gem_request_out(rq);
i915_gem_request_put(rq);
port[0].request = port[1].request;
port[1].request = NULL;
rq = port[0].request;
}
submit = false;
if (!port[1].request)
submit = i915_guc_dequeue(engine);
} while (submit);
}
/* /*
* Everything below here is concerned with setup & teardown, and is * Everything below here is concerned with setup & teardown, and is
* therefore not part of the somewhat time-critical batch-submission * therefore not part of the somewhat time-critical batch-submission
...@@ -810,22 +911,21 @@ static void guc_addon_create(struct intel_guc *guc) ...@@ -810,22 +911,21 @@ static void guc_addon_create(struct intel_guc *guc)
{ {
struct drm_i915_private *dev_priv = guc_to_i915(guc); struct drm_i915_private *dev_priv = guc_to_i915(guc);
struct i915_vma *vma; struct i915_vma *vma;
struct guc_ads *ads;
struct guc_policies *policies;
struct guc_mmio_reg_state *reg_state;
struct intel_engine_cs *engine;
enum intel_engine_id id;
struct page *page; struct page *page;
u32 size;
/* The ads obj includes the struct itself and buffers passed to GuC */ /* The ads obj includes the struct itself and buffers passed to GuC */
size = sizeof(struct guc_ads) + sizeof(struct guc_policies) + struct {
sizeof(struct guc_mmio_reg_state) + struct guc_ads ads;
GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE; struct guc_policies policies;
struct guc_mmio_reg_state reg_state;
u8 reg_state_buffer[GUC_S3_SAVE_SPACE_PAGES * PAGE_SIZE];
} __packed *blob;
struct intel_engine_cs *engine;
enum intel_engine_id id;
u32 base;
vma = guc->ads_vma; vma = guc->ads_vma;
if (!vma) { if (!vma) {
vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(size)); vma = intel_guc_allocate_vma(guc, PAGE_ALIGN(sizeof(*blob)));
if (IS_ERR(vma)) if (IS_ERR(vma))
return; return;
...@@ -833,44 +933,38 @@ static void guc_addon_create(struct intel_guc *guc) ...@@ -833,44 +933,38 @@ static void guc_addon_create(struct intel_guc *guc)
} }
page = i915_vma_first_page(vma); page = i915_vma_first_page(vma);
ads = kmap(page); blob = kmap(page);
/*
* The GuC requires a "Golden Context" when it reinitialises
* engines after a reset. Here we use the Render ring default
* context, which must already exist and be pinned in the GGTT,
* so its address won't change after we've told the GuC where
* to find it.
*/
engine = dev_priv->engine[RCS];
ads->golden_context_lrca = engine->status_page.ggtt_offset;
for_each_engine(engine, dev_priv, id)
ads->eng_state_size[engine->guc_id] = intel_lr_context_size(engine);
/* GuC scheduling policies */ /* GuC scheduling policies */
policies = (void *)ads + sizeof(struct guc_ads); guc_policies_init(&blob->policies);
guc_policies_init(policies);
ads->scheduler_policies =
guc_ggtt_offset(vma) + sizeof(struct guc_ads);
/* MMIO reg state */ /* MMIO reg state */
reg_state = (void *)policies + sizeof(struct guc_policies);
for_each_engine(engine, dev_priv, id) { for_each_engine(engine, dev_priv, id) {
reg_state->mmio_white_list[engine->guc_id].mmio_start = blob->reg_state.mmio_white_list[engine->guc_id].mmio_start =
engine->mmio_base + GUC_MMIO_WHITE_LIST_START; engine->mmio_base + GUC_MMIO_WHITE_LIST_START;
/* Nothing to be saved or restored for now. */ /* Nothing to be saved or restored for now. */
reg_state->mmio_white_list[engine->guc_id].count = 0; blob->reg_state.mmio_white_list[engine->guc_id].count = 0;
} }
ads->reg_state_addr = ads->scheduler_policies + /*
sizeof(struct guc_policies); * The GuC requires a "Golden Context" when it reinitialises
* engines after a reset. Here we use the Render ring default
* context, which must already exist and be pinned in the GGTT,
* so its address won't change after we've told the GuC where
* to find it.
*/
blob->ads.golden_context_lrca =
dev_priv->engine[RCS]->status_page.ggtt_offset;
ads->reg_state_buffer = ads->reg_state_addr + for_each_engine(engine, dev_priv, id)
sizeof(struct guc_mmio_reg_state); blob->ads.eng_state_size[engine->guc_id] =
intel_lr_context_size(engine);
base = guc_ggtt_offset(vma);
blob->ads.scheduler_policies = base + ptr_offset(blob, policies);
blob->ads.reg_state_buffer = base + ptr_offset(blob, reg_state_buffer);
blob->ads.reg_state_addr = base + ptr_offset(blob, reg_state);
kunmap(page); kunmap(page);
} }
...@@ -936,6 +1030,48 @@ static void guc_reset_wq(struct i915_guc_client *client) ...@@ -936,6 +1030,48 @@ static void guc_reset_wq(struct i915_guc_client *client)
client->wq_tail = 0; client->wq_tail = 0;
} }
static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
int irqs;
/* tell all command streamers to forward interrupts (but not vblank) to GuC */
irqs = _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
for_each_engine(engine, dev_priv, id)
I915_WRITE(RING_MODE_GEN7(engine), irqs);
/* route USER_INTERRUPT to Host, all others are sent to GuC. */
irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
/* These three registers have the same bit definitions */
I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
I915_WRITE(GUC_WD_VECS_IER, ~irqs);
/*
* The REDIRECT_TO_GUC bit of the PMINTRMSK register directs all
* (unmasked) PM interrupts to the GuC. All other bits of this
* register *disable* generation of a specific interrupt.
*
* 'pm_intrmsk_mbz' indicates bits that are NOT to be set when
* writing to the PM interrupt mask register, i.e. interrupts
* that must not be disabled.
*
* If the GuC is handling these interrupts, then we must not let
* the PM code disable ANY interrupt that the GuC is expecting.
* So for each ENABLED (0) bit in this register, we must SET the
* bit in pm_intrmsk_mbz so that it's left enabled for the GuC.
* GuC needs ARAT expired interrupt unmasked hence it is set in
* pm_intrmsk_mbz.
*
* Here we CLEAR REDIRECT_TO_GUC bit in pm_intrmsk_mbz, which will
* result in the register bit being left SET!
*/
dev_priv->rps.pm_intrmsk_mbz |= ARAT_EXPIRED_INTRMSK;
dev_priv->rps.pm_intrmsk_mbz &= ~GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
}
int i915_guc_submission_enable(struct drm_i915_private *dev_priv) int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
{ {
struct intel_guc *guc = &dev_priv->guc; struct intel_guc *guc = &dev_priv->guc;
...@@ -952,12 +1088,19 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv) ...@@ -952,12 +1088,19 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
guc_init_doorbell_hw(guc); guc_init_doorbell_hw(guc);
/* Take over from manual control of ELSP (execlists) */ /* Take over from manual control of ELSP (execlists) */
guc_interrupts_capture(dev_priv);
for_each_engine(engine, dev_priv, id) { for_each_engine(engine, dev_priv, id) {
const int wqi_size = sizeof(struct guc_wq_item); const int wqi_size = sizeof(struct guc_wq_item);
struct drm_i915_gem_request *rq; struct drm_i915_gem_request *rq;
engine->submit_request = i915_guc_submit; /* The tasklet was initialised by execlists, and may be in
engine->schedule = NULL; * a state of flux (across a reset) and so we just want to
* take over the callback without changing any other state
* in the tasklet.
*/
engine->irq_tasklet.func = i915_guc_irq_handler;
clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
/* Replay the current set of previously submitted requests */ /* Replay the current set of previously submitted requests */
spin_lock_irq(&engine->timeline->lock); spin_lock_irq(&engine->timeline->lock);
...@@ -971,15 +1114,41 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv) ...@@ -971,15 +1114,41 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
return 0; return 0;
} }
static void guc_interrupts_release(struct drm_i915_private *dev_priv)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
int irqs;
/*
* tell all command streamers NOT to forward interrupts or vblank
* to GuC.
*/
irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
for_each_engine(engine, dev_priv, id)
I915_WRITE(RING_MODE_GEN7(engine), irqs);
/* route all GT interrupts to the host */
I915_WRITE(GUC_BCS_RCS_IER, 0);
I915_WRITE(GUC_VCS2_VCS1_IER, 0);
I915_WRITE(GUC_WD_VECS_IER, 0);
dev_priv->rps.pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
dev_priv->rps.pm_intrmsk_mbz &= ~ARAT_EXPIRED_INTRMSK;
}
void i915_guc_submission_disable(struct drm_i915_private *dev_priv) void i915_guc_submission_disable(struct drm_i915_private *dev_priv)
{ {
struct intel_guc *guc = &dev_priv->guc; struct intel_guc *guc = &dev_priv->guc;
guc_interrupts_release(dev_priv);
if (!guc->execbuf_client) if (!guc->execbuf_client)
return; return;
/* Revert back to manual ELSP submission */ /* Revert back to manual ELSP submission */
intel_execlists_enable_submission(dev_priv); intel_engines_reset_default_submission(dev_priv);
} }
void i915_guc_submission_fini(struct drm_i915_private *dev_priv) void i915_guc_submission_fini(struct drm_i915_private *dev_priv)
......
...@@ -389,11 +389,6 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv) ...@@ -389,11 +389,6 @@ void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv)
spin_unlock_irq(&dev_priv->irq_lock); spin_unlock_irq(&dev_priv->irq_lock);
} }
u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
{
return (mask & ~dev_priv->rps.pm_intr_keep);
}
void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv) void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
{ {
if (!READ_ONCE(dev_priv->rps.interrupts_enabled)) if (!READ_ONCE(dev_priv->rps.interrupts_enabled))
...@@ -728,6 +723,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) ...@@ -728,6 +723,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv, struct intel_crtc *intel_crtc = intel_get_crtc_for_pipe(dev_priv,
pipe); pipe);
const struct drm_display_mode *mode = &intel_crtc->base.hwmode; const struct drm_display_mode *mode = &intel_crtc->base.hwmode;
unsigned long irqflags;
htotal = mode->crtc_htotal; htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start; hsync_start = mode->crtc_hsync_start;
...@@ -744,17 +740,21 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) ...@@ -744,17 +740,21 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
high_frame = PIPEFRAME(pipe); high_frame = PIPEFRAME(pipe);
low_frame = PIPEFRAMEPIXEL(pipe); low_frame = PIPEFRAMEPIXEL(pipe);
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
/* /*
* High & low register fields aren't synchronized, so make sure * High & low register fields aren't synchronized, so make sure
* we get a low value that's stable across two reads of the high * we get a low value that's stable across two reads of the high
* register. * register.
*/ */
do { do {
high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; high1 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
low = I915_READ(low_frame); low = I915_READ_FW(low_frame);
high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK; high2 = I915_READ_FW(high_frame) & PIPE_FRAME_HIGH_MASK;
} while (high1 != high2); } while (high1 != high2);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
high1 >>= PIPE_FRAME_HIGH_SHIFT; high1 >>= PIPE_FRAME_HIGH_SHIFT;
pixel = low & PIPE_PIXEL_MASK; pixel = low & PIPE_PIXEL_MASK;
low >>= PIPE_FRAME_LOW_SHIFT; low >>= PIPE_FRAME_LOW_SHIFT;
...@@ -812,8 +812,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) ...@@ -812,8 +812,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
for (i = 0; i < 100; i++) { for (i = 0; i < 100; i++) {
udelay(1); udelay(1);
temp = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & temp = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
DSL_LINEMASK_GEN3;
if (temp != position) { if (temp != position) {
position = temp; position = temp;
break; break;
...@@ -1057,7 +1056,9 @@ static void notify_ring(struct intel_engine_cs *engine) ...@@ -1057,7 +1056,9 @@ static void notify_ring(struct intel_engine_cs *engine)
* and many waiters. * and many waiters.
*/ */
if (i915_seqno_passed(intel_engine_get_seqno(engine), if (i915_seqno_passed(intel_engine_get_seqno(engine),
wait->seqno)) wait->seqno) &&
!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
&wait->request->fence.flags))
rq = i915_gem_request_get(wait->request); rq = i915_gem_request_get(wait->request);
wake_up_process(wait->tsk); wake_up_process(wait->tsk);
...@@ -1077,73 +1078,51 @@ static void notify_ring(struct intel_engine_cs *engine) ...@@ -1077,73 +1078,51 @@ static void notify_ring(struct intel_engine_cs *engine)
static void vlv_c0_read(struct drm_i915_private *dev_priv, static void vlv_c0_read(struct drm_i915_private *dev_priv,
struct intel_rps_ei *ei) struct intel_rps_ei *ei)
{ {
ei->cz_clock = vlv_punit_read(dev_priv, PUNIT_REG_CZ_TIMESTAMP); ei->ktime = ktime_get_raw();
ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT); ei->render_c0 = I915_READ(VLV_RENDER_C0_COUNT);
ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT); ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
} }
static bool vlv_c0_above(struct drm_i915_private *dev_priv,
const struct intel_rps_ei *old,
const struct intel_rps_ei *now,
int threshold)
{
u64 time, c0;
unsigned int mul = 100;
if (old->cz_clock == 0)
return false;
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
mul <<= 8;
time = now->cz_clock - old->cz_clock;
time *= threshold * dev_priv->czclk_freq;
/* Workload can be split between render + media, e.g. SwapBuffers
* being blitted in X after being rendered in mesa. To account for
* this we need to combine both engines into our activity counter.
*/
c0 = now->render_c0 - old->render_c0;
c0 += now->media_c0 - old->media_c0;
c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC;
return c0 >= time;
}
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv) void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
{ {
vlv_c0_read(dev_priv, &dev_priv->rps.down_ei); memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei));
dev_priv->rps.up_ei = dev_priv->rps.down_ei;
} }
static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir) static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
{ {
const struct intel_rps_ei *prev = &dev_priv->rps.ei;
struct intel_rps_ei now; struct intel_rps_ei now;
u32 events = 0; u32 events = 0;
if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0) if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
return 0; return 0;
vlv_c0_read(dev_priv, &now); vlv_c0_read(dev_priv, &now);
if (now.cz_clock == 0)
return 0;
if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) { if (prev->ktime) {
if (!vlv_c0_above(dev_priv, u64 time, c0;
&dev_priv->rps.down_ei, &now, u32 render, media;
dev_priv->rps.down_threshold))
events |= GEN6_PM_RP_DOWN_THRESHOLD;
dev_priv->rps.down_ei = now;
}
if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) { time = ktime_us_delta(now.ktime, prev->ktime);
if (vlv_c0_above(dev_priv, time *= dev_priv->czclk_freq;
&dev_priv->rps.up_ei, &now,
dev_priv->rps.up_threshold)) /* Workload can be split between render + media,
events |= GEN6_PM_RP_UP_THRESHOLD; * e.g. SwapBuffers being blitted in X after being rendered in
dev_priv->rps.up_ei = now; * mesa. To account for this we need to combine both engines
* into our activity counter.
*/
render = now.render_c0 - prev->render_c0;
media = now.media_c0 - prev->media_c0;
c0 = max(render, media);
c0 *= 1000 * 100 << 8; /* to usecs and scale to threshold% */
if (c0 > time * dev_priv->rps.up_threshold)
events = GEN6_PM_RP_UP_THRESHOLD;
else if (c0 < time * dev_priv->rps.down_threshold)
events = GEN6_PM_RP_DOWN_THRESHOLD;
} }
dev_priv->rps.ei = now;
return events; return events;
} }
...@@ -1163,30 +1142,21 @@ static void gen6_pm_rps_work(struct work_struct *work) ...@@ -1163,30 +1142,21 @@ static void gen6_pm_rps_work(struct work_struct *work)
{ {
struct drm_i915_private *dev_priv = struct drm_i915_private *dev_priv =
container_of(work, struct drm_i915_private, rps.work); container_of(work, struct drm_i915_private, rps.work);
bool client_boost; bool client_boost = false;
int new_delay, adj, min, max; int new_delay, adj, min, max;
u32 pm_iir; u32 pm_iir = 0;
spin_lock_irq(&dev_priv->irq_lock); spin_lock_irq(&dev_priv->irq_lock);
/* Speed up work cancelation during disabling rps interrupts. */ if (dev_priv->rps.interrupts_enabled) {
if (!dev_priv->rps.interrupts_enabled) { pm_iir = fetch_and_zero(&dev_priv->rps.pm_iir);
spin_unlock_irq(&dev_priv->irq_lock); client_boost = fetch_and_zero(&dev_priv->rps.client_boost);
return;
} }
pm_iir = dev_priv->rps.pm_iir;
dev_priv->rps.pm_iir = 0;
/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
client_boost = dev_priv->rps.client_boost;
dev_priv->rps.client_boost = false;
spin_unlock_irq(&dev_priv->irq_lock); spin_unlock_irq(&dev_priv->irq_lock);
/* Make sure we didn't queue anything we're not going to process. */ /* Make sure we didn't queue anything we're not going to process. */
WARN_ON(pm_iir & ~dev_priv->pm_rps_events); WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost) if ((pm_iir & dev_priv->pm_rps_events) == 0 && !client_boost)
return; goto out;
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
...@@ -1243,6 +1213,13 @@ static void gen6_pm_rps_work(struct work_struct *work) ...@@ -1243,6 +1213,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
} }
mutex_unlock(&dev_priv->rps.hw_lock); mutex_unlock(&dev_priv->rps.hw_lock);
out:
/* Make sure not to corrupt PMIMR state used by ringbuffer on GEN6 */
spin_lock_irq(&dev_priv->irq_lock);
if (dev_priv->rps.interrupts_enabled)
gen6_unmask_pm_irq(dev_priv, dev_priv->pm_rps_events);
spin_unlock_irq(&dev_priv->irq_lock);
} }
...@@ -1378,13 +1355,20 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv, ...@@ -1378,13 +1355,20 @@ static void snb_gt_irq_handler(struct drm_i915_private *dev_priv,
static __always_inline void static __always_inline void
gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift) gen8_cs_irq_handler(struct intel_engine_cs *engine, u32 iir, int test_shift)
{ {
if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) bool tasklet = false;
notify_ring(engine);
if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) { if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) {
set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted); set_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
tasklet_hi_schedule(&engine->irq_tasklet); tasklet = true;
}
if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) {
notify_ring(engine);
tasklet |= i915.enable_guc_submission;
} }
if (tasklet)
tasklet_hi_schedule(&engine->irq_tasklet);
} }
static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv, static irqreturn_t gen8_gt_irq_ack(struct drm_i915_private *dev_priv,
...@@ -2647,22 +2631,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) ...@@ -2647,22 +2631,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
return ret; return ret;
} }
static void i915_error_wake_up(struct drm_i915_private *dev_priv)
{
/*
* Notify all waiters for GPU completion events that reset state has
* been changed, and that they need to restart their wait after
* checking for potential errors (and bail out to drop locks if there is
* a gpu reset pending so that i915_error_work_func can acquire them).
*/
/* Wake up __wait_seqno, potentially holding dev->struct_mutex. */
wake_up_all(&dev_priv->gpu_error.wait_queue);
/* Wake up intel_crtc_wait_for_pending_flips, holding crtc->mutex. */
wake_up_all(&dev_priv->pending_flip_queue);
}
/** /**
* i915_reset_and_wakeup - do process context error handling work * i915_reset_and_wakeup - do process context error handling work
* @dev_priv: i915 device private * @dev_priv: i915 device private
...@@ -2682,16 +2650,11 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) ...@@ -2682,16 +2650,11 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
DRM_DEBUG_DRIVER("resetting chip\n"); DRM_DEBUG_DRIVER("resetting chip\n");
kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event); kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
/*
* In most cases it's guaranteed that we get here with an RPM
* reference held, for example because there is a pending GPU
* request that won't finish until the reset is done. This
* isn't the case at least when we get here by doing a
* simulated reset via debugs, so get an RPM reference.
*/
intel_runtime_pm_get(dev_priv);
intel_prepare_reset(dev_priv); intel_prepare_reset(dev_priv);
set_bit(I915_RESET_HANDOFF, &dev_priv->gpu_error.flags);
wake_up_all(&dev_priv->gpu_error.wait_queue);
do { do {
/* /*
* All state reset _must_ be completed before we update the * All state reset _must_ be completed before we update the
...@@ -2706,12 +2669,11 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) ...@@ -2706,12 +2669,11 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
/* We need to wait for anyone holding the lock to wakeup */ /* We need to wait for anyone holding the lock to wakeup */
} while (wait_on_bit_timeout(&dev_priv->gpu_error.flags, } while (wait_on_bit_timeout(&dev_priv->gpu_error.flags,
I915_RESET_IN_PROGRESS, I915_RESET_HANDOFF,
TASK_UNINTERRUPTIBLE, TASK_UNINTERRUPTIBLE,
HZ)); HZ));
intel_finish_reset(dev_priv); intel_finish_reset(dev_priv);
intel_runtime_pm_put(dev_priv);
if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags)) if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags))
kobject_uevent_env(kobj, kobject_uevent_env(kobj,
...@@ -2721,6 +2683,7 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv) ...@@ -2721,6 +2683,7 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
* Note: The wake_up also serves as a memory barrier so that * Note: The wake_up also serves as a memory barrier so that
* waiters see the updated value of the dev_priv->gpu_error. * waiters see the updated value of the dev_priv->gpu_error.
*/ */
clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags);
wake_up_all(&dev_priv->gpu_error.reset_queue); wake_up_all(&dev_priv->gpu_error.reset_queue);
} }
...@@ -2798,31 +2761,29 @@ void i915_handle_error(struct drm_i915_private *dev_priv, ...@@ -2798,31 +2761,29 @@ void i915_handle_error(struct drm_i915_private *dev_priv,
vscnprintf(error_msg, sizeof(error_msg), fmt, args); vscnprintf(error_msg, sizeof(error_msg), fmt, args);
va_end(args); va_end(args);
/*
* In most cases it's guaranteed that we get here with an RPM
* reference held, for example because there is a pending GPU
* request that won't finish until the reset is done. This
* isn't the case at least when we get here by doing a
* simulated reset via debugfs, so get an RPM reference.
*/
intel_runtime_pm_get(dev_priv);
i915_capture_error_state(dev_priv, engine_mask, error_msg); i915_capture_error_state(dev_priv, engine_mask, error_msg);
i915_clear_error_registers(dev_priv); i915_clear_error_registers(dev_priv);
if (!engine_mask) if (!engine_mask)
return; goto out;
if (test_and_set_bit(I915_RESET_IN_PROGRESS, if (test_and_set_bit(I915_RESET_BACKOFF,
&dev_priv->gpu_error.flags)) &dev_priv->gpu_error.flags))
return; goto out;
/*
* Wakeup waiting processes so that the reset function
* i915_reset_and_wakeup doesn't deadlock trying to grab
* various locks. By bumping the reset counter first, the woken
* processes will see a reset in progress and back off,
* releasing their locks and then wait for the reset completion.
* We must do this for _all_ gpu waiters that might hold locks
* that the reset work needs to acquire.
*
* Note: The wake_up also provides a memory barrier to ensure that the
* waiters see the updated value of the reset flags.
*/
i915_error_wake_up(dev_priv);
i915_reset_and_wakeup(dev_priv); i915_reset_and_wakeup(dev_priv);
out:
intel_runtime_pm_put(dev_priv);
} }
/* Called from drm generic code, passed 'crtc' which /* Called from drm generic code, passed 'crtc' which
...@@ -4283,11 +4244,11 @@ void intel_irq_init(struct drm_i915_private *dev_priv) ...@@ -4283,11 +4244,11 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
/* Let's track the enabled rps events */ /* Let's track the enabled rps events */
if (IS_VALLEYVIEW(dev_priv)) if (IS_VALLEYVIEW(dev_priv))
/* WaGsvRC0ResidencyMethod:vlv */ /* WaGsvRC0ResidencyMethod:vlv */
dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED; dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
else else
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
dev_priv->rps.pm_intr_keep = 0; dev_priv->rps.pm_intrmsk_mbz = 0;
/* /*
* SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
...@@ -4296,10 +4257,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv) ...@@ -4296,10 +4257,10 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
* TODO: verify if this can be reproduced on VLV,CHV. * TODO: verify if this can be reproduced on VLV,CHV.
*/ */
if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv)) if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
dev_priv->rps.pm_intr_keep |= GEN6_PM_RP_UP_EI_EXPIRED; dev_priv->rps.pm_intrmsk_mbz |= GEN6_PM_RP_UP_EI_EXPIRED;
if (INTEL_INFO(dev_priv)->gen >= 8) if (INTEL_INFO(dev_priv)->gen >= 8)
dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_GUC; dev_priv->rps.pm_intrmsk_mbz |= GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC;
if (IS_GEN2(dev_priv)) { if (IS_GEN2(dev_priv)) {
/* Gen2 doesn't have a hardware frame counter */ /* Gen2 doesn't have a hardware frame counter */
......
...@@ -59,6 +59,8 @@ struct i915_params i915 __read_mostly = { ...@@ -59,6 +59,8 @@ struct i915_params i915 __read_mostly = {
.enable_guc_loading = 0, .enable_guc_loading = 0,
.enable_guc_submission = 0, .enable_guc_submission = 0,
.guc_log_level = -1, .guc_log_level = -1,
.guc_firmware_path = NULL,
.huc_firmware_path = NULL,
.enable_dp_mst = true, .enable_dp_mst = true,
.inject_load_failure = 0, .inject_load_failure = 0,
.enable_dpcd_backlight = false, .enable_dpcd_backlight = false,
...@@ -230,6 +232,14 @@ module_param_named(guc_log_level, i915.guc_log_level, int, 0400); ...@@ -230,6 +232,14 @@ module_param_named(guc_log_level, i915.guc_log_level, int, 0400);
MODULE_PARM_DESC(guc_log_level, MODULE_PARM_DESC(guc_log_level,
"GuC firmware logging level (-1:disabled (default), 0-3:enabled)"); "GuC firmware logging level (-1:disabled (default), 0-3:enabled)");
module_param_named_unsafe(guc_firmware_path, i915.guc_firmware_path, charp, 0400);
MODULE_PARM_DESC(guc_firmware_path,
"GuC firmware path to use instead of the default one");
module_param_named_unsafe(huc_firmware_path, i915.huc_firmware_path, charp, 0400);
MODULE_PARM_DESC(huc_firmware_path,
"HuC firmware path to use instead of the default one");
module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool, 0600); module_param_named_unsafe(enable_dp_mst, i915.enable_dp_mst, bool, 0600);
MODULE_PARM_DESC(enable_dp_mst, MODULE_PARM_DESC(enable_dp_mst,
"Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)"); "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)");
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
func(int, enable_guc_loading); \ func(int, enable_guc_loading); \
func(int, enable_guc_submission); \ func(int, enable_guc_submission); \
func(int, guc_log_level); \ func(int, guc_log_level); \
func(char *, guc_firmware_path); \
func(char *, huc_firmware_path); \
func(int, use_mmio_flip); \ func(int, use_mmio_flip); \
func(int, mmio_debug); \ func(int, mmio_debug); \
func(int, edp_vswing); \ func(int, edp_vswing); \
......
...@@ -1140,8 +1140,6 @@ enum skl_disp_power_wells { ...@@ -1140,8 +1140,6 @@ enum skl_disp_power_wells {
#define VLV_BIAS_CPU_125_SOC_875 (6 << 2) #define VLV_BIAS_CPU_125_SOC_875 (6 << 2)
#define CHV_BIAS_CPU_50_SOC_50 (3 << 2) #define CHV_BIAS_CPU_50_SOC_50 (3 << 2)
#define VLV_CZ_CLOCK_TO_MILLI_SEC 100000
/* vlv2 north clock has */ /* vlv2 north clock has */
#define CCK_FUSE_REG 0x8 #define CCK_FUSE_REG 0x8
#define CCK_FUSE_HPLL_FREQ_MASK 0x3 #define CCK_FUSE_HPLL_FREQ_MASK 0x3
...@@ -7453,7 +7451,8 @@ enum { ...@@ -7453,7 +7451,8 @@ enum {
#define VLV_RCEDATA _MMIO(0xA0BC) #define VLV_RCEDATA _MMIO(0xA0BC)
#define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0) #define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0)
#define GEN6_PMINTRMSK _MMIO(0xA168) #define GEN6_PMINTRMSK _MMIO(0xA168)
#define GEN8_PMINTR_REDIRECT_TO_GUC (1<<31) #define GEN8_PMINTR_DISABLE_REDIRECT_TO_GUC (1<<31)
#define ARAT_EXPIRED_INTRMSK (1<<9)
#define GEN8_MISC_CTRL0 _MMIO(0xA180) #define GEN8_MISC_CTRL0 _MMIO(0xA180)
#define VLV_PWRDWNUPCTL _MMIO(0xA294) #define VLV_PWRDWNUPCTL _MMIO(0xA294)
#define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4) #define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4)
......
...@@ -42,32 +42,8 @@ static inline struct drm_i915_private *kdev_minor_to_i915(struct device *kdev) ...@@ -42,32 +42,8 @@ static inline struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
static u32 calc_residency(struct drm_i915_private *dev_priv, static u32 calc_residency(struct drm_i915_private *dev_priv,
i915_reg_t reg) i915_reg_t reg)
{ {
u64 raw_time; /* 32b value may overflow during fixed point math */ return DIV_ROUND_CLOSEST_ULL(intel_rc6_residency_us(dev_priv, reg),
u64 units = 128ULL, div = 100000ULL; 1000);
u32 ret;
if (!intel_enable_rc6())
return 0;
intel_runtime_pm_get(dev_priv);
/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
units = 1;
div = dev_priv->czclk_freq;
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
units <<= 8;
} else if (IS_GEN9_LP(dev_priv)) {
units = 1;
div = 1200; /* 833.33ns */
}
raw_time = I915_READ(reg) * units;
ret = DIV_ROUND_UP_ULL(raw_time, div);
intel_runtime_pm_put(dev_priv);
return ret;
} }
static ssize_t static ssize_t
......
...@@ -590,7 +590,7 @@ TRACE_EVENT(i915_gem_request_queue, ...@@ -590,7 +590,7 @@ TRACE_EVENT(i915_gem_request_queue,
TP_fast_assign( TP_fast_assign(
__entry->dev = req->i915->drm.primary->index; __entry->dev = req->i915->drm.primary->index;
__entry->ring = req->engine->id; __entry->ring = req->engine->id;
__entry->ctx = req->ctx->hw_id; __entry->ctx = req->fence.context;
__entry->seqno = req->fence.seqno; __entry->seqno = req->fence.seqno;
__entry->flags = flags; __entry->flags = flags;
), ),
...@@ -637,8 +637,8 @@ DECLARE_EVENT_CLASS(i915_gem_request, ...@@ -637,8 +637,8 @@ DECLARE_EVENT_CLASS(i915_gem_request,
TP_fast_assign( TP_fast_assign(
__entry->dev = req->i915->drm.primary->index; __entry->dev = req->i915->drm.primary->index;
__entry->ctx = req->ctx->hw_id;
__entry->ring = req->engine->id; __entry->ring = req->engine->id;
__entry->ctx = req->fence.context;
__entry->seqno = req->fence.seqno; __entry->seqno = req->fence.seqno;
__entry->global = req->global_seqno; __entry->global = req->global_seqno;
), ),
...@@ -681,7 +681,7 @@ DECLARE_EVENT_CLASS(i915_gem_request_hw, ...@@ -681,7 +681,7 @@ DECLARE_EVENT_CLASS(i915_gem_request_hw,
TP_fast_assign( TP_fast_assign(
__entry->dev = req->i915->drm.primary->index; __entry->dev = req->i915->drm.primary->index;
__entry->ring = req->engine->id; __entry->ring = req->engine->id;
__entry->ctx = req->ctx->hw_id; __entry->ctx = req->fence.context;
__entry->seqno = req->fence.seqno; __entry->seqno = req->fence.seqno;
__entry->global_seqno = req->global_seqno; __entry->global_seqno = req->global_seqno;
__entry->port = port; __entry->port = port;
...@@ -776,7 +776,7 @@ TRACE_EVENT(i915_gem_request_wait_begin, ...@@ -776,7 +776,7 @@ TRACE_EVENT(i915_gem_request_wait_begin,
TP_fast_assign( TP_fast_assign(
__entry->dev = req->i915->drm.primary->index; __entry->dev = req->i915->drm.primary->index;
__entry->ring = req->engine->id; __entry->ring = req->engine->id;
__entry->ctx = req->ctx->hw_id; __entry->ctx = req->fence.context;
__entry->seqno = req->fence.seqno; __entry->seqno = req->fence.seqno;
__entry->global = req->global_seqno; __entry->global = req->global_seqno;
__entry->flags = flags; __entry->flags = flags;
......
...@@ -66,6 +66,8 @@ ...@@ -66,6 +66,8 @@
#define ptr_pack_bits(ptr, bits) \ #define ptr_pack_bits(ptr, bits) \
((typeof(ptr))((unsigned long)(ptr) | (bits))) ((typeof(ptr))((unsigned long)(ptr) | (bits)))
#define ptr_offset(ptr, member) offsetof(typeof(*(ptr)), member)
#define fetch_and_zero(ptr) ({ \ #define fetch_and_zero(ptr) ({ \
typeof(*ptr) __T = *(ptr); \ typeof(*ptr) __T = *(ptr); \
*(ptr) = (typeof(*ptr))0; \ *(ptr) = (typeof(*ptr))0; \
......
...@@ -218,13 +218,9 @@ int intel_vgt_balloon(struct drm_i915_private *dev_priv) ...@@ -218,13 +218,9 @@ int intel_vgt_balloon(struct drm_i915_private *dev_priv)
goto err; goto err;
} }
/* if (unmappable_end < ggtt_end) {
* No need to partition out the last physical page,
* because it is reserved to the guard page.
*/
if (unmappable_end < ggtt_end - PAGE_SIZE) {
ret = vgt_balloon_space(ggtt, &bl_info.space[3], ret = vgt_balloon_space(ggtt, &bl_info.space[3],
unmappable_end, ggtt_end - PAGE_SIZE); unmappable_end, ggtt_end);
if (ret) if (ret)
goto err; goto err;
} }
......
...@@ -1341,6 +1341,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, ...@@ -1341,6 +1341,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
return; return;
} }
/* Common defaults which may be overridden by VBT. */
static void static void
init_vbt_defaults(struct drm_i915_private *dev_priv) init_vbt_defaults(struct drm_i915_private *dev_priv)
{ {
...@@ -1377,6 +1378,18 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) ...@@ -1377,6 +1378,18 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
&dev_priv->vbt.ddi_port_info[port]; &dev_priv->vbt.ddi_port_info[port];
info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN; info->hdmi_level_shift = HDMI_LEVEL_SHIFT_UNKNOWN;
}
}
/* Defaults to initialize only if there is no VBT. */
static void
init_vbt_missing_defaults(struct drm_i915_private *dev_priv)
{
enum port port;
for (port = PORT_A; port < I915_MAX_PORTS; port++) {
struct ddi_vbt_port_info *info =
&dev_priv->vbt.ddi_port_info[port];
info->supports_dvi = (port != PORT_A && port != PORT_E); info->supports_dvi = (port != PORT_A && port != PORT_E);
info->supports_hdmi = info->supports_dvi; info->supports_hdmi = info->supports_dvi;
...@@ -1462,36 +1475,35 @@ static const struct vbt_header *find_vbt(void __iomem *bios, size_t size) ...@@ -1462,36 +1475,35 @@ static const struct vbt_header *find_vbt(void __iomem *bios, size_t size)
* intel_bios_init - find VBT and initialize settings from the BIOS * intel_bios_init - find VBT and initialize settings from the BIOS
* @dev_priv: i915 device instance * @dev_priv: i915 device instance
* *
* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers * Parse and initialize settings from the Video BIOS Tables (VBT). If the VBT
* to appropriate values. * was not found in ACPI OpRegion, try to find it in PCI ROM first. Also
* * initialize some defaults if the VBT is not present at all.
* Returns 0 on success, nonzero on failure.
*/ */
int void intel_bios_init(struct drm_i915_private *dev_priv)
intel_bios_init(struct drm_i915_private *dev_priv)
{ {
struct pci_dev *pdev = dev_priv->drm.pdev; struct pci_dev *pdev = dev_priv->drm.pdev;
const struct vbt_header *vbt = dev_priv->opregion.vbt; const struct vbt_header *vbt = dev_priv->opregion.vbt;
const struct bdb_header *bdb; const struct bdb_header *bdb;
u8 __iomem *bios = NULL; u8 __iomem *bios = NULL;
if (HAS_PCH_NOP(dev_priv)) if (HAS_PCH_NOP(dev_priv)) {
return -ENODEV; DRM_DEBUG_KMS("Skipping VBT init due to disabled display.\n");
return;
}
init_vbt_defaults(dev_priv); init_vbt_defaults(dev_priv);
/* If the OpRegion does not have VBT, look in PCI ROM. */
if (!vbt) { if (!vbt) {
size_t size; size_t size;
bios = pci_map_rom(pdev, &size); bios = pci_map_rom(pdev, &size);
if (!bios) if (!bios)
return -1; goto out;
vbt = find_vbt(bios, size); vbt = find_vbt(bios, size);
if (!vbt) { if (!vbt)
pci_unmap_rom(pdev, bios); goto out;
return -1;
}
DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n"); DRM_DEBUG_KMS("Found valid VBT in PCI ROM\n");
} }
...@@ -1516,10 +1528,14 @@ intel_bios_init(struct drm_i915_private *dev_priv) ...@@ -1516,10 +1528,14 @@ intel_bios_init(struct drm_i915_private *dev_priv)
parse_mipi_sequence(dev_priv, bdb); parse_mipi_sequence(dev_priv, bdb);
parse_ddi_ports(dev_priv, bdb); parse_ddi_ports(dev_priv, bdb);
out:
if (!vbt) {
DRM_INFO("Failed to find VBIOS tables (VBT)\n");
init_vbt_missing_defaults(dev_priv);
}
if (bios) if (bios)
pci_unmap_rom(pdev, bios); pci_unmap_rom(pdev, bios);
return 0;
} }
/** /**
......
...@@ -47,12 +47,11 @@ static unsigned int __intel_breadcrumbs_wakeup(struct intel_breadcrumbs *b) ...@@ -47,12 +47,11 @@ static unsigned int __intel_breadcrumbs_wakeup(struct intel_breadcrumbs *b)
unsigned int intel_engine_wakeup(struct intel_engine_cs *engine) unsigned int intel_engine_wakeup(struct intel_engine_cs *engine)
{ {
struct intel_breadcrumbs *b = &engine->breadcrumbs; struct intel_breadcrumbs *b = &engine->breadcrumbs;
unsigned long flags;
unsigned int result; unsigned int result;
spin_lock_irqsave(&b->irq_lock, flags); spin_lock_irq(&b->irq_lock);
result = __intel_breadcrumbs_wakeup(b); result = __intel_breadcrumbs_wakeup(b);
spin_unlock_irqrestore(&b->irq_lock, flags); spin_unlock_irq(&b->irq_lock);
return result; return result;
} }
...@@ -86,7 +85,7 @@ static void intel_breadcrumbs_hangcheck(unsigned long data) ...@@ -86,7 +85,7 @@ static void intel_breadcrumbs_hangcheck(unsigned long data)
return; return;
} }
/* We keep the hangcheck time alive until we disarm the irq, even /* We keep the hangcheck timer alive until we disarm the irq, even
* if there are no waiters at present. * if there are no waiters at present.
* *
* If the waiter was currently running, assume it hasn't had a chance * If the waiter was currently running, assume it hasn't had a chance
...@@ -110,20 +109,18 @@ static void intel_breadcrumbs_fake_irq(unsigned long data) ...@@ -110,20 +109,18 @@ static void intel_breadcrumbs_fake_irq(unsigned long data)
{ {
struct intel_engine_cs *engine = (struct intel_engine_cs *)data; struct intel_engine_cs *engine = (struct intel_engine_cs *)data;
struct intel_breadcrumbs *b = &engine->breadcrumbs; struct intel_breadcrumbs *b = &engine->breadcrumbs;
unsigned long flags;
/* /* The timer persists in case we cannot enable interrupts,
* The timer persists in case we cannot enable interrupts,
* or if we have previously seen seqno/interrupt incoherency * or if we have previously seen seqno/interrupt incoherency
* ("missed interrupt" syndrome). Here the worker will wake up * ("missed interrupt" syndrome, better known as a "missed breadcrumb").
* every jiffie in order to kick the oldest waiter to do the * Here the worker will wake up every jiffie in order to kick the
* coherent seqno check. * oldest waiter to do the coherent seqno check.
*/ */
spin_lock_irqsave(&b->irq_lock, flags); spin_lock_irq(&b->irq_lock);
if (!__intel_breadcrumbs_wakeup(b)) if (!__intel_breadcrumbs_wakeup(b))
__intel_engine_disarm_breadcrumbs(engine); __intel_engine_disarm_breadcrumbs(engine);
spin_unlock_irqrestore(&b->irq_lock, flags); spin_unlock_irq(&b->irq_lock);
if (!b->irq_armed) if (!b->irq_armed)
return; return;
...@@ -168,6 +165,7 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) ...@@ -168,6 +165,7 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
struct intel_breadcrumbs *b = &engine->breadcrumbs; struct intel_breadcrumbs *b = &engine->breadcrumbs;
lockdep_assert_held(&b->irq_lock); lockdep_assert_held(&b->irq_lock);
GEM_BUG_ON(b->irq_wait);
if (b->irq_enabled) { if (b->irq_enabled) {
irq_disable(engine); irq_disable(engine);
...@@ -180,23 +178,31 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) ...@@ -180,23 +178,31 @@ void __intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine) void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
{ {
struct intel_breadcrumbs *b = &engine->breadcrumbs; struct intel_breadcrumbs *b = &engine->breadcrumbs;
unsigned long flags; struct intel_wait *wait, *n, *first;
if (!b->irq_armed) if (!b->irq_armed)
return; return;
spin_lock_irqsave(&b->irq_lock, flags);
/* We only disarm the irq when we are idle (all requests completed), /* We only disarm the irq when we are idle (all requests completed),
* so if there remains a sleeping waiter, it missed the request * so if the bottom-half remains asleep, it missed the request
* completion. * completion.
*/ */
if (__intel_breadcrumbs_wakeup(b) & ENGINE_WAKEUP_ASLEEP)
missed_breadcrumb(engine);
spin_lock_irq(&b->rb_lock);
spin_lock(&b->irq_lock);
first = fetch_and_zero(&b->irq_wait);
__intel_engine_disarm_breadcrumbs(engine); __intel_engine_disarm_breadcrumbs(engine);
spin_unlock(&b->irq_lock);
rbtree_postorder_for_each_entry_safe(wait, n, &b->waiters, node) {
RB_CLEAR_NODE(&wait->node);
if (wake_up_process(wait->tsk) && wait == first)
missed_breadcrumb(engine);
}
b->waiters = RB_ROOT;
spin_unlock_irqrestore(&b->irq_lock, flags); spin_unlock_irq(&b->rb_lock);
} }
static bool use_fake_irq(const struct intel_breadcrumbs *b) static bool use_fake_irq(const struct intel_breadcrumbs *b)
...@@ -280,9 +286,15 @@ static inline void __intel_breadcrumbs_finish(struct intel_breadcrumbs *b, ...@@ -280,9 +286,15 @@ static inline void __intel_breadcrumbs_finish(struct intel_breadcrumbs *b,
struct intel_wait *wait) struct intel_wait *wait)
{ {
lockdep_assert_held(&b->rb_lock); lockdep_assert_held(&b->rb_lock);
GEM_BUG_ON(b->irq_wait == wait);
/* This request is completed, so remove it from the tree, mark it as /* This request is completed, so remove it from the tree, mark it as
* complete, and *then* wake up the associated task. * complete, and *then* wake up the associated task. N.B. when the
* task wakes up, it will find the empty rb_node, discern that it
* has already been removed from the tree and skip the serialisation
* of the b->rb_lock and b->irq_lock. This means that the destruction
* of the intel_wait is not serialised with the interrupt handler
* by the waiter - it must instead be serialised by the caller.
*/ */
rb_erase(&wait->node, &b->waiters); rb_erase(&wait->node, &b->waiters);
RB_CLEAR_NODE(&wait->node); RB_CLEAR_NODE(&wait->node);
...@@ -297,6 +309,7 @@ static inline void __intel_breadcrumbs_next(struct intel_engine_cs *engine, ...@@ -297,6 +309,7 @@ static inline void __intel_breadcrumbs_next(struct intel_engine_cs *engine,
spin_lock(&b->irq_lock); spin_lock(&b->irq_lock);
GEM_BUG_ON(!b->irq_armed); GEM_BUG_ON(!b->irq_armed);
GEM_BUG_ON(!b->irq_wait);
b->irq_wait = to_wait(next); b->irq_wait = to_wait(next);
spin_unlock(&b->irq_lock); spin_unlock(&b->irq_lock);
...@@ -372,25 +385,8 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine, ...@@ -372,25 +385,8 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
rb_link_node(&wait->node, parent, p); rb_link_node(&wait->node, parent, p);
rb_insert_color(&wait->node, &b->waiters); rb_insert_color(&wait->node, &b->waiters);
if (completed) {
struct rb_node *next = rb_next(completed);
GEM_BUG_ON(!next && !first);
if (next && next != &wait->node) {
GEM_BUG_ON(first);
__intel_breadcrumbs_next(engine, next);
}
do {
struct intel_wait *crumb = to_wait(completed);
completed = rb_prev(completed);
__intel_breadcrumbs_finish(b, crumb);
} while (completed);
}
if (first) { if (first) {
spin_lock(&b->irq_lock); spin_lock(&b->irq_lock);
GEM_BUG_ON(rb_first(&b->waiters) != &wait->node);
b->irq_wait = wait; b->irq_wait = wait;
/* After assigning ourselves as the new bottom-half, we must /* After assigning ourselves as the new bottom-half, we must
* perform a cursory check to prevent a missed interrupt. * perform a cursory check to prevent a missed interrupt.
...@@ -403,7 +399,28 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine, ...@@ -403,7 +399,28 @@ static bool __intel_engine_add_wait(struct intel_engine_cs *engine,
__intel_breadcrumbs_enable_irq(b); __intel_breadcrumbs_enable_irq(b);
spin_unlock(&b->irq_lock); spin_unlock(&b->irq_lock);
} }
if (completed) {
/* Advance the bottom-half (b->irq_wait) before we wake up
* the waiters who may scribble over their intel_wait
* just as the interrupt handler is dereferencing it via
* b->irq_wait.
*/
if (!first) {
struct rb_node *next = rb_next(completed);
GEM_BUG_ON(next == &wait->node);
__intel_breadcrumbs_next(engine, next);
}
do {
struct intel_wait *crumb = to_wait(completed);
completed = rb_prev(completed);
__intel_breadcrumbs_finish(b, crumb);
} while (completed);
}
GEM_BUG_ON(!b->irq_wait); GEM_BUG_ON(!b->irq_wait);
GEM_BUG_ON(!b->irq_armed);
GEM_BUG_ON(rb_first(&b->waiters) != &b->irq_wait->node); GEM_BUG_ON(rb_first(&b->waiters) != &b->irq_wait->node);
return first; return first;
...@@ -505,8 +522,10 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine, ...@@ -505,8 +522,10 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
* the tree by the bottom-half to avoid contention on the spinlock * the tree by the bottom-half to avoid contention on the spinlock
* by the herd. * by the herd.
*/ */
if (RB_EMPTY_NODE(&wait->node)) if (RB_EMPTY_NODE(&wait->node)) {
GEM_BUG_ON(READ_ONCE(b->irq_wait) == wait);
return; return;
}
spin_lock_irq(&b->rb_lock); spin_lock_irq(&b->rb_lock);
__intel_engine_remove_wait(engine, wait); __intel_engine_remove_wait(engine, wait);
...@@ -643,7 +662,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request) ...@@ -643,7 +662,7 @@ void intel_engine_enable_signaling(struct drm_i915_gem_request *request)
/* Note that we may be called from an interrupt handler on another /* Note that we may be called from an interrupt handler on another
* device (e.g. nouveau signaling a fence completion causing us * device (e.g. nouveau signaling a fence completion causing us
* to submit a request, and so enable signaling). As such, * to submit a request, and so enable signaling). As such,
* we need to make sure that all other users of b->lock protect * we need to make sure that all other users of b->rb_lock protect
* against interrupts, i.e. use spin_lock_irqsave. * against interrupts, i.e. use spin_lock_irqsave.
*/ */
...@@ -822,12 +841,12 @@ bool intel_breadcrumbs_busy(struct intel_engine_cs *engine) ...@@ -822,12 +841,12 @@ bool intel_breadcrumbs_busy(struct intel_engine_cs *engine)
if (b->irq_wait) { if (b->irq_wait) {
wake_up_process(b->irq_wait->tsk); wake_up_process(b->irq_wait->tsk);
busy |= intel_engine_flag(engine); busy = true;
} }
if (rcu_access_pointer(b->first_signal)) { if (rcu_access_pointer(b->first_signal)) {
wake_up_process(b->signaler); wake_up_process(b->signaler);
busy |= intel_engine_flag(engine); busy = true;
} }
spin_unlock_irq(&b->rb_lock); spin_unlock_irq(&b->rb_lock);
......
...@@ -223,7 +223,7 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv) ...@@ -223,7 +223,7 @@ static unsigned int intel_hpll_vco(struct drm_i915_private *dev_priv)
/* FIXME other chipsets? */ /* FIXME other chipsets? */
if (IS_GM45(dev_priv)) if (IS_GM45(dev_priv))
vco_table = ctg_vco; vco_table = ctg_vco;
else if (IS_G4X(dev_priv)) else if (IS_G45(dev_priv))
vco_table = elk_vco; vco_table = elk_vco;
else if (IS_I965GM(dev_priv)) else if (IS_I965GM(dev_priv))
vco_table = cl_vco; vco_table = cl_vco;
...@@ -1470,7 +1470,7 @@ static int intel_max_pixel_rate(struct drm_atomic_state *state) ...@@ -1470,7 +1470,7 @@ static int intel_max_pixel_rate(struct drm_atomic_state *state)
memcpy(intel_state->min_pixclk, dev_priv->min_pixclk, memcpy(intel_state->min_pixclk, dev_priv->min_pixclk,
sizeof(intel_state->min_pixclk)); sizeof(intel_state->min_pixclk));
for_each_crtc_in_state(state, crtc, cstate, i) { for_each_new_crtc_in_state(state, crtc, cstate, i) {
int pixel_rate; int pixel_rate;
crtc_state = to_intel_crtc_state(cstate); crtc_state = to_intel_crtc_state(cstate);
...@@ -1859,7 +1859,7 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv) ...@@ -1859,7 +1859,7 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk; dev_priv->display.get_cdclk = fixed_450mhz_get_cdclk;
else if (IS_GM45(dev_priv)) else if (IS_GM45(dev_priv))
dev_priv->display.get_cdclk = gm45_get_cdclk; dev_priv->display.get_cdclk = gm45_get_cdclk;
else if (IS_G4X(dev_priv)) else if (IS_G45(dev_priv))
dev_priv->display.get_cdclk = g33_get_cdclk; dev_priv->display.get_cdclk = g33_get_cdclk;
else if (IS_I965GM(dev_priv)) else if (IS_I965GM(dev_priv))
dev_priv->display.get_cdclk = i965gm_get_cdclk; dev_priv->display.get_cdclk = i965gm_get_cdclk;
......
...@@ -465,14 +465,14 @@ static void glk_load_degamma_lut(struct drm_crtc_state *state) ...@@ -465,14 +465,14 @@ static void glk_load_degamma_lut(struct drm_crtc_state *state)
* different values per channel, so this just loads a linear table. * different values per channel, so this just loads a linear table.
*/ */
for (i = 0; i < lut_size; i++) { for (i = 0; i < lut_size; i++) {
uint32_t v = (i * ((1 << 16) - 1)) / (lut_size - 1); uint32_t v = (i * (1 << 16)) / (lut_size - 1);
I915_WRITE(PRE_CSC_GAMC_DATA(pipe), v); I915_WRITE(PRE_CSC_GAMC_DATA(pipe), v);
} }
/* Clamp values > 1.0. */ /* Clamp values > 1.0. */
while (i++ < 35) while (i++ < 35)
I915_WRITE(PRE_CSC_GAMC_DATA(pipe), (1 << 16) - 1); I915_WRITE(PRE_CSC_GAMC_DATA(pipe), (1 << 16));
} }
static void glk_load_luts(struct drm_crtc_state *state) static void glk_load_luts(struct drm_crtc_state *state)
......
...@@ -34,9 +34,8 @@ ...@@ -34,9 +34,8 @@
* low-power state and comes back to normal. * low-power state and comes back to normal.
*/ */
#define I915_CSR_GLK "i915/glk_dmc_ver1_03.bin" #define I915_CSR_GLK "i915/glk_dmc_ver1_04.bin"
MODULE_FIRMWARE(I915_CSR_GLK); #define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 4)
#define GLK_CSR_VERSION_REQUIRED CSR_VERSION(1, 3)
#define I915_CSR_KBL "i915/kbl_dmc_ver1_01.bin" #define I915_CSR_KBL "i915/kbl_dmc_ver1_01.bin"
MODULE_FIRMWARE(I915_CSR_KBL); MODULE_FIRMWARE(I915_CSR_KBL);
......
...@@ -821,11 +821,11 @@ static struct intel_encoder * ...@@ -821,11 +821,11 @@ static struct intel_encoder *
intel_ddi_get_crtc_encoder(struct intel_crtc *crtc) intel_ddi_get_crtc_encoder(struct intel_crtc *crtc)
{ {
struct drm_device *dev = crtc->base.dev; struct drm_device *dev = crtc->base.dev;
struct intel_encoder *intel_encoder, *ret = NULL; struct intel_encoder *encoder, *ret = NULL;
int num_encoders = 0; int num_encoders = 0;
for_each_encoder_on_crtc(dev, &crtc->base, intel_encoder) { for_each_encoder_on_crtc(dev, &crtc->base, encoder) {
ret = intel_encoder; ret = encoder;
num_encoders++; num_encoders++;
} }
...@@ -837,7 +837,7 @@ intel_ddi_get_crtc_encoder(struct intel_crtc *crtc) ...@@ -837,7 +837,7 @@ intel_ddi_get_crtc_encoder(struct intel_crtc *crtc)
return ret; return ret;
} }
struct intel_encoder * static struct intel_encoder *
intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
{ {
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
...@@ -850,7 +850,7 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) ...@@ -850,7 +850,7 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state)
state = crtc_state->base.state; state = crtc_state->base.state;
for_each_connector_in_state(state, connector, connector_state, i) { for_each_new_connector_in_state(state, connector, connector_state, i) {
if (connector_state->crtc != crtc_state->base.crtc) if (connector_state->crtc != crtc_state->base.crtc)
continue; continue;
...@@ -1130,12 +1130,12 @@ void intel_ddi_clock_get(struct intel_encoder *encoder, ...@@ -1130,12 +1130,12 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
static bool static bool
hsw_ddi_pll_select(struct intel_crtc *intel_crtc, hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state, struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder) struct intel_encoder *encoder)
{ {
struct intel_shared_dpll *pll; struct intel_shared_dpll *pll;
pll = intel_get_shared_dpll(intel_crtc, crtc_state, pll = intel_get_shared_dpll(intel_crtc, crtc_state,
intel_encoder); encoder);
if (!pll) if (!pll)
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(intel_crtc->pipe)); pipe_name(intel_crtc->pipe));
...@@ -1146,11 +1146,11 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, ...@@ -1146,11 +1146,11 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
static bool static bool
skl_ddi_pll_select(struct intel_crtc *intel_crtc, skl_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state, struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder) struct intel_encoder *encoder)
{ {
struct intel_shared_dpll *pll; struct intel_shared_dpll *pll;
pll = intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder); pll = intel_get_shared_dpll(intel_crtc, crtc_state, encoder);
if (pll == NULL) { if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n", DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(intel_crtc->pipe)); pipe_name(intel_crtc->pipe));
...@@ -1163,9 +1163,9 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, ...@@ -1163,9 +1163,9 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
static bool static bool
bxt_ddi_pll_select(struct intel_crtc *intel_crtc, bxt_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state, struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder) struct intel_encoder *encoder)
{ {
return !!intel_get_shared_dpll(intel_crtc, crtc_state, intel_encoder); return !!intel_get_shared_dpll(intel_crtc, crtc_state, encoder);
} }
/* /*
...@@ -1179,27 +1179,27 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc, ...@@ -1179,27 +1179,27 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
struct intel_crtc_state *crtc_state) struct intel_crtc_state *crtc_state)
{ {
struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
struct intel_encoder *intel_encoder = struct intel_encoder *encoder =
intel_ddi_get_crtc_new_encoder(crtc_state); intel_ddi_get_crtc_new_encoder(crtc_state);
if (IS_GEN9_BC(dev_priv)) if (IS_GEN9_BC(dev_priv))
return skl_ddi_pll_select(intel_crtc, crtc_state, return skl_ddi_pll_select(intel_crtc, crtc_state,
intel_encoder); encoder);
else if (IS_GEN9_LP(dev_priv)) else if (IS_GEN9_LP(dev_priv))
return bxt_ddi_pll_select(intel_crtc, crtc_state, return bxt_ddi_pll_select(intel_crtc, crtc_state,
intel_encoder); encoder);
else else
return hsw_ddi_pll_select(intel_crtc, crtc_state, return hsw_ddi_pll_select(intel_crtc, crtc_state,
intel_encoder); encoder);
} }
void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state) void intel_ddi_set_pipe_settings(const struct intel_crtc_state *crtc_state)
{ {
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
int type = intel_encoder->type; int type = encoder->type;
uint32_t temp; uint32_t temp;
if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) { if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
...@@ -1244,12 +1244,12 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state, ...@@ -1244,12 +1244,12 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state)
{ {
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe; enum pipe pipe = crtc->pipe;
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
enum port port = intel_ddi_get_encoder_port(intel_encoder); enum port port = intel_ddi_get_encoder_port(encoder);
int type = intel_encoder->type; int type = encoder->type;
uint32_t temp; uint32_t temp;
/* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */ /* Enable TRANS_DDI_FUNC_CTL for the pipe to work in HDMI mode */
...@@ -1321,7 +1321,7 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state) ...@@ -1321,7 +1321,7 @@ void intel_ddi_enable_transcoder_func(const struct intel_crtc_state *crtc_state)
temp |= DDI_PORT_WIDTH(crtc_state->lane_count); temp |= DDI_PORT_WIDTH(crtc_state->lane_count);
} else { } else {
WARN(1, "Invalid encoder type %d for pipe %c\n", WARN(1, "Invalid encoder type %d for pipe %c\n",
intel_encoder->type, pipe_name(pipe)); encoder->type, pipe_name(pipe));
} }
I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp); I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
...@@ -1342,19 +1342,19 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ...@@ -1342,19 +1342,19 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
{ {
struct drm_device *dev = intel_connector->base.dev; struct drm_device *dev = intel_connector->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_encoder *intel_encoder = intel_connector->encoder; struct intel_encoder *encoder = intel_connector->encoder;
int type = intel_connector->base.connector_type; int type = intel_connector->base.connector_type;
enum port port = intel_ddi_get_encoder_port(intel_encoder); enum port port = intel_ddi_get_encoder_port(encoder);
enum pipe pipe = 0; enum pipe pipe = 0;
enum transcoder cpu_transcoder; enum transcoder cpu_transcoder;
uint32_t tmp; uint32_t tmp;
bool ret; bool ret;
if (!intel_display_power_get_if_enabled(dev_priv, if (!intel_display_power_get_if_enabled(dev_priv,
intel_encoder->power_domain)) encoder->power_domain))
return false; return false;
if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) { if (!encoder->get_hw_state(encoder, &pipe)) {
ret = false; ret = false;
goto out; goto out;
} }
...@@ -1393,7 +1393,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ...@@ -1393,7 +1393,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
} }
out: out:
intel_display_power_put(dev_priv, intel_encoder->power_domain); intel_display_power_put(dev_priv, encoder->power_domain);
return ret; return ret;
} }
...@@ -1486,8 +1486,8 @@ void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state) ...@@ -1486,8 +1486,8 @@ void intel_ddi_enable_pipe_clock(const struct intel_crtc_state *crtc_state)
{ {
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct intel_encoder *encoder = intel_ddi_get_crtc_encoder(crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder); enum port port = intel_ddi_get_encoder_port(encoder);
enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; enum transcoder cpu_transcoder = crtc_state->cpu_transcoder;
if (cpu_transcoder != TRANSCODER_EDP) if (cpu_transcoder != TRANSCODER_EDP)
...@@ -1762,14 +1762,14 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder, ...@@ -1762,14 +1762,14 @@ static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
crtc_state, conn_state); crtc_state, conn_state);
} }
static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder, static void intel_ddi_pre_enable(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config, struct intel_crtc_state *pipe_config,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
{ {
int type = intel_encoder->type; int type = encoder->type;
if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) { if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
intel_ddi_pre_enable_dp(intel_encoder, intel_ddi_pre_enable_dp(encoder,
pipe_config->port_clock, pipe_config->port_clock,
pipe_config->lane_count, pipe_config->lane_count,
pipe_config->shared_dpll, pipe_config->shared_dpll,
...@@ -1777,7 +1777,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder, ...@@ -1777,7 +1777,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
INTEL_OUTPUT_DP_MST)); INTEL_OUTPUT_DP_MST));
} }
if (type == INTEL_OUTPUT_HDMI) { if (type == INTEL_OUTPUT_HDMI) {
intel_ddi_pre_enable_hdmi(intel_encoder, intel_ddi_pre_enable_hdmi(encoder,
pipe_config->has_hdmi_sink, pipe_config->has_hdmi_sink,
pipe_config, conn_state, pipe_config, conn_state,
pipe_config->shared_dpll); pipe_config->shared_dpll);
...@@ -1836,11 +1836,11 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder, ...@@ -1836,11 +1836,11 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
} }
} }
void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder, void intel_ddi_fdi_post_disable(struct intel_encoder *encoder,
struct intel_crtc_state *old_crtc_state, struct intel_crtc_state *old_crtc_state,
struct drm_connector_state *old_conn_state) struct drm_connector_state *old_conn_state)
{ {
struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev); struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
uint32_t val; uint32_t val;
/* /*
...@@ -1853,7 +1853,7 @@ void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder, ...@@ -1853,7 +1853,7 @@ void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
val &= ~FDI_RX_ENABLE; val &= ~FDI_RX_ENABLE;
I915_WRITE(FDI_RX_CTL(PIPE_A), val); I915_WRITE(FDI_RX_CTL(PIPE_A), val);
intel_ddi_post_disable(intel_encoder, old_crtc_state, old_conn_state); intel_ddi_post_disable(encoder, old_crtc_state, old_conn_state);
val = I915_READ(FDI_RX_MISC(PIPE_A)); val = I915_READ(FDI_RX_MISC(PIPE_A));
val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK); val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
......
...@@ -197,8 +197,10 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) ...@@ -197,8 +197,10 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1; IS_GEN9_LP(dev_priv) && sseu_subslice_total(sseu) > 1;
sseu->has_eu_pg = sseu->eu_per_subslice > 2; sseu->has_eu_pg = sseu->eu_per_subslice > 2;
if (IS_BROXTON(dev_priv)) { if (IS_GEN9_LP(dev_priv)) {
#define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss))) #define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss)))
info->has_pooled_eu = hweight8(sseu->subslice_mask) == 3;
/* /*
* There is a HW issue in 2x6 fused down parts that requires * There is a HW issue in 2x6 fused down parts that requires
* Pooled EU to be enabled as a WA. The pool configuration * Pooled EU to be enabled as a WA. The pool configuration
...@@ -206,9 +208,8 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv) ...@@ -206,9 +208,8 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
* doesn't affect if the device has all 3 subslices enabled. * doesn't affect if the device has all 3 subslices enabled.
*/ */
/* WaEnablePooledEuFor2x6:bxt */ /* WaEnablePooledEuFor2x6:bxt */
info->has_pooled_eu = ((hweight8(sseu->subslice_mask) == 3) || info->has_pooled_eu |= (hweight8(sseu->subslice_mask) == 2 &&
(hweight8(sseu->subslice_mask) == 2 && IS_BXT_REVID(dev_priv, 0, BXT_REVID_B_LAST));
INTEL_REVID(dev_priv) < BXT_REVID_C0));
sseu->min_eu_in_pool = 0; sseu->min_eu_in_pool = 0;
if (info->has_pooled_eu) { if (info->has_pooled_eu) {
......
...@@ -1188,7 +1188,13 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask); ...@@ -1188,7 +1188,13 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_reset_rps_interrupts(struct drm_i915_private *dev_priv);
void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_enable_rps_interrupts(struct drm_i915_private *dev_priv);
void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv); void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv);
u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask);
static inline u32 gen6_sanitize_rps_pm_mask(const struct drm_i915_private *i915,
u32 mask)
{
return mask & ~i915->rps.pm_intrmsk_mbz;
}
void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv); void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv); void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv) static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
...@@ -1239,8 +1245,6 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv, ...@@ -1239,8 +1245,6 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
struct intel_crtc *intel_crtc); struct intel_crtc *intel_crtc);
void intel_ddi_get_config(struct intel_encoder *encoder, void intel_ddi_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config); struct intel_crtc_state *pipe_config);
struct intel_encoder *
intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state);
void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
void intel_ddi_clock_get(struct intel_encoder *encoder, void intel_ddi_clock_get(struct intel_encoder *encoder,
...@@ -1250,12 +1254,8 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state, ...@@ -1250,12 +1254,8 @@ void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state,
uint32_t ddi_signal_levels(struct intel_dp *intel_dp); uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder); u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
unsigned int intel_fb_align_height(struct drm_i915_private *dev_priv, unsigned int intel_fb_align_height(const struct drm_framebuffer *fb,
unsigned int height, int plane, unsigned int height);
uint32_t pixel_format,
uint64_t fb_format_modifier);
u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
uint64_t fb_modifier, uint32_t pixel_format);
/* intel_audio.c */ /* intel_audio.c */
void intel_init_audio_hooks(struct drm_i915_private *dev_priv); void intel_init_audio_hooks(struct drm_i915_private *dev_priv);
...@@ -1269,6 +1269,10 @@ void intel_audio_init(struct drm_i915_private *dev_priv); ...@@ -1269,6 +1269,10 @@ void intel_audio_init(struct drm_i915_private *dev_priv);
void intel_audio_deinit(struct drm_i915_private *dev_priv); void intel_audio_deinit(struct drm_i915_private *dev_priv);
/* intel_cdclk.c */ /* intel_cdclk.c */
void skl_init_cdclk(struct drm_i915_private *dev_priv);
void skl_uninit_cdclk(struct drm_i915_private *dev_priv);
void bxt_init_cdclk(struct drm_i915_private *dev_priv);
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv);
void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv); void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv);
void intel_update_max_cdclk(struct drm_i915_private *dev_priv); void intel_update_max_cdclk(struct drm_i915_private *dev_priv);
void intel_update_cdclk(struct drm_i915_private *dev_priv); void intel_update_cdclk(struct drm_i915_private *dev_priv);
...@@ -1380,9 +1384,6 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, ...@@ -1380,9 +1384,6 @@ int intel_plane_atomic_set_property(struct drm_plane *plane,
int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state); struct drm_plane_state *plane_state);
unsigned int intel_tile_height(const struct drm_i915_private *dev_priv,
uint64_t fb_modifier, unsigned int cpp);
void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv, void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe); enum pipe pipe);
...@@ -1414,14 +1415,10 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv); ...@@ -1414,14 +1415,10 @@ void intel_prepare_reset(struct drm_i915_private *dev_priv);
void intel_finish_reset(struct drm_i915_private *dev_priv); void intel_finish_reset(struct drm_i915_private *dev_priv);
void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_enable_pc8(struct drm_i915_private *dev_priv);
void hsw_disable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv);
void bxt_init_cdclk(struct drm_i915_private *dev_priv);
void bxt_uninit_cdclk(struct drm_i915_private *dev_priv);
void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv); void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv);
void bxt_enable_dc9(struct drm_i915_private *dev_priv); void bxt_enable_dc9(struct drm_i915_private *dev_priv);
void bxt_disable_dc9(struct drm_i915_private *dev_priv); void bxt_disable_dc9(struct drm_i915_private *dev_priv);
void gen9_enable_dc5(struct drm_i915_private *dev_priv); void gen9_enable_dc5(struct drm_i915_private *dev_priv);
void skl_init_cdclk(struct drm_i915_private *dev_priv);
void skl_uninit_cdclk(struct drm_i915_private *dev_priv);
unsigned int skl_cdclk_get_vco(unsigned int freq); unsigned int skl_cdclk_get_vco(unsigned int freq);
void skl_enable_dc6(struct drm_i915_private *dev_priv); void skl_enable_dc6(struct drm_i915_private *dev_priv);
void skl_disable_dc6(struct drm_i915_private *dev_priv); void skl_disable_dc6(struct drm_i915_private *dev_priv);
......
此差异已折叠。
...@@ -39,7 +39,6 @@ struct intel_dsi_host; ...@@ -39,7 +39,6 @@ struct intel_dsi_host;
struct intel_dsi { struct intel_dsi {
struct intel_encoder base; struct intel_encoder base;
struct drm_panel *panel;
struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS]; struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
/* GPIO Desc for CRC based Panel control */ /* GPIO Desc for CRC based Panel control */
...@@ -130,11 +129,11 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) ...@@ -130,11 +129,11 @@ static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
return container_of(encoder, struct intel_dsi, base.base); return container_of(encoder, struct intel_dsi, base.base);
} }
/* intel_dsi.c */
void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port); void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port);
enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt);
void intel_dsi_exec_vbt_sequence(struct intel_dsi *intel_dsi, /* intel_dsi_pll.c */
enum mipi_seq seq_id);
bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv); bool intel_dsi_pll_is_enabled(struct drm_i915_private *dev_priv);
int intel_compute_dsi_pll(struct intel_encoder *encoder, int intel_compute_dsi_pll(struct intel_encoder *encoder,
struct intel_crtc_state *config); struct intel_crtc_state *config);
...@@ -146,7 +145,10 @@ u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp, ...@@ -146,7 +145,10 @@ u32 intel_dsi_get_pclk(struct intel_encoder *encoder, int pipe_bpp,
void intel_dsi_reset_clocks(struct intel_encoder *encoder, void intel_dsi_reset_clocks(struct intel_encoder *encoder,
enum port port); enum port port);
struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id); /* intel_dsi_vbt.c */
enum mipi_dsi_pixel_format pixel_format_from_register_bits(u32 fmt); bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id);
int intel_dsi_vbt_get_modes(struct intel_dsi *intel_dsi);
void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
enum mipi_seq seq_id);
#endif /* _INTEL_DSI_H */ #endif /* _INTEL_DSI_H */
...@@ -105,6 +105,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv, ...@@ -105,6 +105,8 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
/* Nothing to do here, execute in order of dependencies */ /* Nothing to do here, execute in order of dependencies */
engine->schedule = NULL; engine->schedule = NULL;
ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier);
dev_priv->engine[id] = engine; dev_priv->engine[id] = engine;
return 0; return 0;
} }
...@@ -191,6 +193,7 @@ int intel_engines_init(struct drm_i915_private *dev_priv) ...@@ -191,6 +193,7 @@ int intel_engines_init(struct drm_i915_private *dev_priv)
goto cleanup; goto cleanup;
} }
GEM_BUG_ON(!engine->submit_request);
mask |= ENGINE_MASK(id); mask |= ENGINE_MASK(id);
} }
...@@ -248,8 +251,7 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno) ...@@ -248,8 +251,7 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
} }
intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno); intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
if (engine->irq_seqno_barrier) clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
engine->irq_seqno_barrier(engine);
GEM_BUG_ON(i915_gem_active_isset(&engine->timeline->last_request)); GEM_BUG_ON(i915_gem_active_isset(&engine->timeline->last_request));
engine->hangcheck.seqno = seqno; engine->hangcheck.seqno = seqno;
...@@ -342,6 +344,8 @@ int intel_engine_init_common(struct intel_engine_cs *engine) ...@@ -342,6 +344,8 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
{ {
int ret; int ret;
engine->set_default_submission(engine);
/* We may need to do things with the shrinker which /* We may need to do things with the shrinker which
* require us to immediately switch back to the default * require us to immediately switch back to the default
* context. This can cause a problem as pinning the * context. This can cause a problem as pinning the
...@@ -1115,6 +1119,15 @@ bool intel_engines_are_idle(struct drm_i915_private *dev_priv) ...@@ -1115,6 +1119,15 @@ bool intel_engines_are_idle(struct drm_i915_private *dev_priv)
return true; return true;
} }
void intel_engines_reset_default_submission(struct drm_i915_private *i915)
{
struct intel_engine_cs *engine;
enum intel_engine_id id;
for_each_engine(engine, i915, id)
engine->set_default_submission(engine);
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftests/mock_engine.c" #include "selftests/mock_engine.c"
#endif #endif
...@@ -1061,7 +1061,7 @@ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv, ...@@ -1061,7 +1061,7 @@ void intel_fbc_choose_crtc(struct drm_i915_private *dev_priv,
* plane. We could go for fancier schemes such as checking the plane * plane. We could go for fancier schemes such as checking the plane
* size, but this would just affect the few platforms that don't tie FBC * size, but this would just affect the few platforms that don't tie FBC
* to pipe or plane A. */ * to pipe or plane A. */
for_each_plane_in_state(state, plane, plane_state, i) { for_each_new_plane_in_state(state, plane, plane_state, i) {
struct intel_plane_state *intel_plane_state = struct intel_plane_state *intel_plane_state =
to_intel_plane_state(plane_state); to_intel_plane_state(plane_state);
struct intel_crtc_state *intel_crtc_state; struct intel_crtc_state *intel_crtc_state;
......
...@@ -619,9 +619,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, ...@@ -619,9 +619,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
} }
cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay; cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
cur_size = intel_fb_align_height(to_i915(dev), cur_size, cur_size = intel_fb_align_height(&fb->base, 0, cur_size);
fb->base.format->format,
fb->base.modifier);
cur_size *= fb->base.pitches[0]; cur_size *= fb->base.pitches[0];
DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n", DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
pipe_name(intel_crtc->pipe), pipe_name(intel_crtc->pipe),
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册