mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 22:24:09 +08:00
Merge tag 'drm-intel-next-2016-09-19' of git://anongit.freedesktop.org/drm-intel into drm-next
- refactor the sseu code (Imre) - refine guc dmesg output (Dave Gordon) - more vgpu work - more skl wm fixes (Lyude) - refactor dpll code in prep for upfront link training (Jim Bride et al) - consolidate all platform feature checks into intel_device_info (Carlos Santa) - refactor elsp/execlist submission as prep for re-submission after hang recovery and eventually scheduling (Chris Wilson) - allow synchronous gpu reset handling, to remove tricky/impossible/fragile error recovery code (Chris Wilson) - prep work for nonblocking (execlist) submission, using fences to track depencies and drive elsp submission (Chris Wilson) - partial error recover/resubmission of non-guilty batches after hangs (Chris Wilson) - full dma-buf implicit fencing support (Chris Wilson) - dp link training fixes (Jim, Dhinkaran, Navare, ...) - obey dp branch device pixel rate/bpc/clock limits (Mika Kahola), needed for many vga dongles - bunch of small cleanups and polish all over, as usual [airlied: printing macros collided] * tag 'drm-intel-next-2016-09-19' of git://anongit.freedesktop.org/drm-intel: (163 commits) drm/i915: Update DRIVER_DATE to 20160919 drm: Fix DisplayPort branch device ID kernel-doc drm/i915: use NULL for NULL pointers drm/i915: do not use 'false' as a NULL pointer drm/i915: make intel_dp_compute_bpp static drm: Add DP branch device info on debugfs drm/i915: Update bits per component for display info drm/i915: Check pixel rate for DP to VGA dongle drm/i915: Read DP branch device SW revision drm/i915: Read DP branch device HW revision drm/i915: Cleanup DisplayPort AUX channel initialization drm: Read DP branch device id drm: Helper to read max bits per component drm: Helper to read max clock rate drm: Drop VGA from bpc definitions drm: Add missing DP downstream port types drm/i915: Add ddb size field to device info structure drm/i915/guc: general tidying up (submission) drm/i915/guc: general tidying up (loader) drm/i915: clarify PMINTRMSK/pm_intr_keep usage ...
This commit is contained in:
commit
b81a6179b6
@ -507,8 +507,7 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
||||
INTEL_I915GM_IDS(&gen3_early_ops),
|
||||
INTEL_I945G_IDS(&gen3_early_ops),
|
||||
INTEL_I945GM_IDS(&gen3_early_ops),
|
||||
INTEL_VLV_M_IDS(&gen6_early_ops),
|
||||
INTEL_VLV_D_IDS(&gen6_early_ops),
|
||||
INTEL_VLV_IDS(&gen6_early_ops),
|
||||
INTEL_PINEVIEW_IDS(&gen3_early_ops),
|
||||
INTEL_I965G_IDS(&gen3_early_ops),
|
||||
INTEL_G33_IDS(&gen3_early_ops),
|
||||
@ -521,10 +520,8 @@ static const struct pci_device_id intel_early_ids[] __initconst = {
|
||||
INTEL_SNB_M_IDS(&gen6_early_ops),
|
||||
INTEL_IVB_M_IDS(&gen6_early_ops),
|
||||
INTEL_IVB_D_IDS(&gen6_early_ops),
|
||||
INTEL_HSW_D_IDS(&gen6_early_ops),
|
||||
INTEL_HSW_M_IDS(&gen6_early_ops),
|
||||
INTEL_BDW_M_IDS(&gen8_early_ops),
|
||||
INTEL_BDW_D_IDS(&gen8_early_ops),
|
||||
INTEL_HSW_IDS(&gen6_early_ops),
|
||||
INTEL_BDW_IDS(&gen8_early_ops),
|
||||
INTEL_CHV_IDS(&chv_early_ops),
|
||||
INTEL_SKL_IDS(&gen9_early_ops),
|
||||
INTEL_BXT_IDS(&gen9_early_ops),
|
||||
|
@ -439,6 +439,179 @@ int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_link_configure);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_clock() - extract branch device max
|
||||
* pixel rate for legacy VGA
|
||||
* converter or max TMDS clock
|
||||
* rate for others
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
*
|
||||
* Returns max clock in kHz on success or 0 if max clock not defined
|
||||
*/
|
||||
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
{
|
||||
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
|
||||
if (!detailed_cap_info)
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
return port_cap[1] * 8 * 1000;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
return port_cap[1] * 2500;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_clock);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_max_bpc() - extract branch device max
|
||||
* bits per component
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
*
|
||||
* Returns max bpc on success or 0 if max bpc not defined
|
||||
*/
|
||||
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4])
|
||||
{
|
||||
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
int bpc;
|
||||
|
||||
if (!detailed_cap_info)
|
||||
return 0;
|
||||
|
||||
switch (type) {
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
bpc = port_cap[2] & DP_DS_MAX_BPC_MASK;
|
||||
|
||||
switch (bpc) {
|
||||
case DP_DS_8BPC:
|
||||
return 8;
|
||||
case DP_DS_10BPC:
|
||||
return 10;
|
||||
case DP_DS_12BPC:
|
||||
return 12;
|
||||
case DP_DS_16BPC:
|
||||
return 16;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_max_bpc);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_id() - identify branch device
|
||||
* @aux: DisplayPort AUX channel
|
||||
* @id: DisplayPort branch device id
|
||||
*
|
||||
* Returns branch device id on success or NULL on failure
|
||||
*/
|
||||
int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6])
|
||||
{
|
||||
return drm_dp_dpcd_read(aux, DP_BRANCH_ID, id, 6);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_id);
|
||||
|
||||
/**
|
||||
* drm_dp_downstream_debug() - debug DP branch devices
|
||||
* @m: pointer for debugfs file
|
||||
* @dpcd: DisplayPort configuration data
|
||||
* @port_cap: port capabilities
|
||||
* @aux: DisplayPort AUX channel
|
||||
*
|
||||
*/
|
||||
void drm_dp_downstream_debug(struct seq_file *m,
|
||||
const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], struct drm_dp_aux *aux)
|
||||
{
|
||||
bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DETAILED_CAP_INFO_AVAILABLE;
|
||||
int clk;
|
||||
int bpc;
|
||||
char id[6];
|
||||
int len;
|
||||
uint8_t rev[2];
|
||||
int type = port_cap[0] & DP_DS_PORT_TYPE_MASK;
|
||||
bool branch_device = dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DWN_STRM_PORT_PRESENT;
|
||||
|
||||
seq_printf(m, "\tDP branch device present: %s\n",
|
||||
branch_device ? "yes" : "no");
|
||||
|
||||
if (!branch_device)
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case DP_DS_PORT_TYPE_DP:
|
||||
seq_puts(m, "\t\tType: DisplayPort\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_VGA:
|
||||
seq_puts(m, "\t\tType: VGA\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_DVI:
|
||||
seq_puts(m, "\t\tType: DVI\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_HDMI:
|
||||
seq_puts(m, "\t\tType: HDMI\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_NON_EDID:
|
||||
seq_puts(m, "\t\tType: others without EDID support\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_DP_DUALMODE:
|
||||
seq_puts(m, "\t\tType: DP++\n");
|
||||
break;
|
||||
case DP_DS_PORT_TYPE_WIRELESS:
|
||||
seq_puts(m, "\t\tType: Wireless\n");
|
||||
break;
|
||||
default:
|
||||
seq_puts(m, "\t\tType: N/A\n");
|
||||
}
|
||||
|
||||
drm_dp_downstream_id(aux, id);
|
||||
seq_printf(m, "\t\tID: %s\n", id);
|
||||
|
||||
len = drm_dp_dpcd_read(aux, DP_BRANCH_HW_REV, &rev[0], 1);
|
||||
if (len > 0)
|
||||
seq_printf(m, "\t\tHW: %d.%d\n",
|
||||
(rev[0] & 0xf0) >> 4, rev[0] & 0xf);
|
||||
|
||||
len = drm_dp_dpcd_read(aux, DP_BRANCH_SW_REV, &rev, 2);
|
||||
if (len > 0)
|
||||
seq_printf(m, "\t\tSW: %d.%d\n", rev[0], rev[1]);
|
||||
|
||||
if (detailed_cap_info) {
|
||||
clk = drm_dp_downstream_max_clock(dpcd, port_cap);
|
||||
|
||||
if (clk > 0) {
|
||||
if (type == DP_DS_PORT_TYPE_VGA)
|
||||
seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk);
|
||||
else
|
||||
seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk);
|
||||
}
|
||||
|
||||
bpc = drm_dp_downstream_max_bpc(dpcd, port_cap);
|
||||
|
||||
if (bpc > 0)
|
||||
seq_printf(m, "\t\tMax bpc: %d\n", bpc);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_dp_downstream_debug);
|
||||
|
||||
/*
|
||||
* I2C-over-AUX implementation
|
||||
*/
|
||||
|
@ -16,6 +16,7 @@ i915-y := i915_drv.o \
|
||||
i915_params.o \
|
||||
i915_pci.o \
|
||||
i915_suspend.o \
|
||||
i915_sw_fence.o \
|
||||
i915_sysfs.o \
|
||||
intel_csr.o \
|
||||
intel_device_info.o \
|
||||
|
@ -984,7 +984,7 @@ static u32 *copy_batch(struct drm_i915_gem_object *dst_obj,
|
||||
|
||||
src = ERR_PTR(-ENODEV);
|
||||
if (src_needs_clflush &&
|
||||
i915_memcpy_from_wc((void *)(uintptr_t)batch_start_offset, 0, 0)) {
|
||||
i915_memcpy_from_wc((void *)(uintptr_t)batch_start_offset, NULL, 0)) {
|
||||
src = i915_gem_object_pin_map(src_obj, I915_MAP_WC);
|
||||
if (!IS_ERR(src)) {
|
||||
i915_memcpy_from_wc(dst,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -77,7 +77,7 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static bool shown_bug_once;
|
||||
struct device *dev = dev_priv->drm.dev;
|
||||
struct device *kdev = dev_priv->drm.dev;
|
||||
bool is_error = level[1] <= KERN_ERR[1];
|
||||
bool is_debug = level[1] == KERN_DEBUG[1];
|
||||
struct va_format vaf;
|
||||
@ -91,11 +91,11 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
|
||||
dev_printk(level, dev, "[" DRM_NAME ":%ps] %pV",
|
||||
dev_printk(level, kdev, "[" DRM_NAME ":%ps] %pV",
|
||||
__builtin_return_address(0), &vaf);
|
||||
|
||||
if (is_error && !shown_bug_once) {
|
||||
dev_notice(dev, "%s", FDO_BUG_MSG);
|
||||
dev_notice(kdev, "%s", FDO_BUG_MSG);
|
||||
shown_bug_once = true;
|
||||
}
|
||||
|
||||
@ -232,6 +232,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
drm_i915_getparam_t *param = data;
|
||||
int value;
|
||||
|
||||
@ -242,13 +243,10 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
/* Reject all old ums/dri params. */
|
||||
return -ENODEV;
|
||||
case I915_PARAM_CHIPSET_ID:
|
||||
value = dev->pdev->device;
|
||||
value = pdev->device;
|
||||
break;
|
||||
case I915_PARAM_REVISION:
|
||||
value = dev->pdev->revision;
|
||||
break;
|
||||
case I915_PARAM_HAS_GEM:
|
||||
value = 1;
|
||||
value = pdev->revision;
|
||||
break;
|
||||
case I915_PARAM_NUM_FENCES_AVAIL:
|
||||
value = dev_priv->num_fence_regs;
|
||||
@ -256,13 +254,6 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
case I915_PARAM_HAS_OVERLAY:
|
||||
value = dev_priv->overlay ? 1 : 0;
|
||||
break;
|
||||
case I915_PARAM_HAS_PAGEFLIPPING:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXECBUF2:
|
||||
/* depends on GEM */
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_BSD:
|
||||
value = intel_engine_initialized(&dev_priv->engine[VCS]);
|
||||
break;
|
||||
@ -275,67 +266,34 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
case I915_PARAM_HAS_BSD2:
|
||||
value = intel_engine_initialized(&dev_priv->engine[VCS2]);
|
||||
break;
|
||||
case I915_PARAM_HAS_RELAXED_FENCING:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_COHERENT_RINGS:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_CONSTANTS:
|
||||
value = INTEL_INFO(dev)->gen >= 4;
|
||||
break;
|
||||
case I915_PARAM_HAS_RELAXED_DELTA:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_GEN7_SOL_RESET:
|
||||
value = 1;
|
||||
value = INTEL_GEN(dev_priv) >= 4;
|
||||
break;
|
||||
case I915_PARAM_HAS_LLC:
|
||||
value = HAS_LLC(dev);
|
||||
value = HAS_LLC(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_WT:
|
||||
value = HAS_WT(dev);
|
||||
value = HAS_WT(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_ALIASING_PPGTT:
|
||||
value = USES_PPGTT(dev);
|
||||
break;
|
||||
case I915_PARAM_HAS_WAIT_TIMEOUT:
|
||||
value = 1;
|
||||
value = USES_PPGTT(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_SEMAPHORES:
|
||||
value = i915.semaphores;
|
||||
break;
|
||||
case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_SECURE_BATCHES:
|
||||
value = capable(CAP_SYS_ADMIN);
|
||||
break;
|
||||
case I915_PARAM_HAS_PINNED_BATCHES:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_NO_RELOC:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_HANDLE_LUT:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_CMD_PARSER_VERSION:
|
||||
value = i915_cmd_parser_get_version(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_COHERENT_PHYS_GTT:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_MMAP_VERSION:
|
||||
value = 1;
|
||||
break;
|
||||
case I915_PARAM_SUBSLICE_TOTAL:
|
||||
value = INTEL_INFO(dev)->subslice_total;
|
||||
value = sseu_subslice_total(&INTEL_INFO(dev_priv)->sseu);
|
||||
if (!value)
|
||||
return -ENODEV;
|
||||
break;
|
||||
case I915_PARAM_EU_TOTAL:
|
||||
value = INTEL_INFO(dev)->eu_total;
|
||||
value = INTEL_INFO(dev_priv)->sseu.eu_total;
|
||||
if (!value)
|
||||
return -ENODEV;
|
||||
break;
|
||||
@ -343,16 +301,43 @@ static int i915_getparam(struct drm_device *dev, void *data,
|
||||
value = i915.enable_hangcheck && intel_has_gpu_reset(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_RESOURCE_STREAMER:
|
||||
value = HAS_RESOURCE_STREAMER(dev);
|
||||
break;
|
||||
case I915_PARAM_HAS_EXEC_SOFTPIN:
|
||||
value = 1;
|
||||
value = HAS_RESOURCE_STREAMER(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_HAS_POOLED_EU:
|
||||
value = HAS_POOLED_EU(dev);
|
||||
value = HAS_POOLED_EU(dev_priv);
|
||||
break;
|
||||
case I915_PARAM_MIN_EU_IN_POOL:
|
||||
value = INTEL_INFO(dev)->min_eu_in_pool;
|
||||
value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool;
|
||||
break;
|
||||
case I915_PARAM_MMAP_GTT_VERSION:
|
||||
/* Though we've started our numbering from 1, and so class all
|
||||
* earlier versions as 0, in effect their value is undefined as
|
||||
* the ioctl will report EINVAL for the unknown param!
|
||||
*/
|
||||
value = i915_gem_mmap_gtt_version();
|
||||
break;
|
||||
case I915_PARAM_MMAP_VERSION:
|
||||
/* Remember to bump this if the version changes! */
|
||||
case I915_PARAM_HAS_GEM:
|
||||
case I915_PARAM_HAS_PAGEFLIPPING:
|
||||
case I915_PARAM_HAS_EXECBUF2: /* depends on GEM */
|
||||
case I915_PARAM_HAS_RELAXED_FENCING:
|
||||
case I915_PARAM_HAS_COHERENT_RINGS:
|
||||
case I915_PARAM_HAS_RELAXED_DELTA:
|
||||
case I915_PARAM_HAS_GEN7_SOL_RESET:
|
||||
case I915_PARAM_HAS_WAIT_TIMEOUT:
|
||||
case I915_PARAM_HAS_PRIME_VMAP_FLUSH:
|
||||
case I915_PARAM_HAS_PINNED_BATCHES:
|
||||
case I915_PARAM_HAS_EXEC_NO_RELOC:
|
||||
case I915_PARAM_HAS_EXEC_HANDLE_LUT:
|
||||
case I915_PARAM_HAS_COHERENT_PHYS_GTT:
|
||||
case I915_PARAM_HAS_EXEC_SOFTPIN:
|
||||
/* For the time being all of these are always true;
|
||||
* if some supported hardware does not have one of these
|
||||
* features this value needs to be provided from
|
||||
* INTEL_INFO(), a feature macro, or similar.
|
||||
*/
|
||||
value = 1;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG("Unknown parameter %d\n", param->param);
|
||||
@ -516,7 +501,7 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
|
||||
pr_info("switched on\n");
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
|
||||
/* i915 resume handler doesn't set to D0 */
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
i915_resume_switcheroo(dev);
|
||||
dev->switch_power_state = DRM_SWITCH_POWER_ON;
|
||||
} else {
|
||||
@ -574,7 +559,6 @@ static void i915_gem_fini(struct drm_device *dev)
|
||||
}
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
i915_gem_reset(dev);
|
||||
i915_gem_cleanup_engines(dev);
|
||||
i915_gem_context_fini(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
@ -585,6 +569,7 @@ static void i915_gem_fini(struct drm_device *dev)
|
||||
static int i915_load_modeset_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int ret;
|
||||
|
||||
if (i915_inject_load_failure())
|
||||
@ -601,13 +586,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
||||
* then we do not take part in VGA arbitration and the
|
||||
* vga_client_register() fails with -ENODEV.
|
||||
*/
|
||||
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
|
||||
ret = vga_client_register(pdev, dev, NULL, i915_vga_set_decode);
|
||||
if (ret && ret != -ENODEV)
|
||||
goto out;
|
||||
|
||||
intel_register_dsm_handler();
|
||||
|
||||
ret = vga_switcheroo_register_client(dev->pdev, &i915_switcheroo_ops, false);
|
||||
ret = vga_switcheroo_register_client(pdev, &i915_switcheroo_ops, false);
|
||||
if (ret)
|
||||
goto cleanup_vga_client;
|
||||
|
||||
@ -659,9 +644,9 @@ cleanup_irq:
|
||||
cleanup_csr:
|
||||
intel_csr_ucode_fini(dev_priv);
|
||||
intel_power_domains_fini(dev_priv);
|
||||
vga_switcheroo_unregister_client(dev->pdev);
|
||||
vga_switcheroo_unregister_client(pdev);
|
||||
cleanup_vga_client:
|
||||
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
||||
vga_client_register(pdev, NULL, NULL, NULL);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -849,7 +834,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
|
||||
intel_init_audio_hooks(dev_priv);
|
||||
i915_gem_load_init(&dev_priv->drm);
|
||||
|
||||
intel_display_crc_init(&dev_priv->drm);
|
||||
intel_display_crc_init(dev_priv);
|
||||
|
||||
intel_device_info_dump(dev_priv);
|
||||
|
||||
@ -881,6 +866,7 @@ static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
|
||||
static int i915_mmio_setup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int mmio_bar;
|
||||
int mmio_size;
|
||||
|
||||
@ -897,7 +883,7 @@ static int i915_mmio_setup(struct drm_device *dev)
|
||||
mmio_size = 512 * 1024;
|
||||
else
|
||||
mmio_size = 2 * 1024 * 1024;
|
||||
dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size);
|
||||
dev_priv->regs = pci_iomap(pdev, mmio_bar, mmio_size);
|
||||
if (dev_priv->regs == NULL) {
|
||||
DRM_ERROR("failed to map registers\n");
|
||||
|
||||
@ -913,9 +899,10 @@ static int i915_mmio_setup(struct drm_device *dev)
|
||||
static void i915_mmio_cleanup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
intel_teardown_mchbar(dev);
|
||||
pci_iounmap(dev->pdev, dev_priv->regs);
|
||||
pci_iounmap(pdev, dev_priv->regs);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -994,6 +981,7 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
int ret;
|
||||
|
||||
@ -1032,11 +1020,11 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
|
||||
goto out_ggtt;
|
||||
}
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* overlay on gen2 is broken and can't address above 1G */
|
||||
if (IS_GEN2(dev)) {
|
||||
ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30));
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(30));
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to set DMA mask\n");
|
||||
|
||||
@ -1053,7 +1041,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
|
||||
* which also needs to be handled carefully.
|
||||
*/
|
||||
if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) {
|
||||
ret = dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32));
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to set DMA mask\n");
|
||||
@ -1083,7 +1071,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
|
||||
* stuck interrupts on some machines.
|
||||
*/
|
||||
if (!IS_I945G(dev) && !IS_I945GM(dev)) {
|
||||
if (pci_enable_msi(dev->pdev) < 0)
|
||||
if (pci_enable_msi(pdev) < 0)
|
||||
DRM_DEBUG_DRIVER("can't enable MSI");
|
||||
}
|
||||
|
||||
@ -1101,10 +1089,10 @@ out_ggtt:
|
||||
*/
|
||||
static void i915_driver_cleanup_hw(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
if (dev->pdev->msi_enabled)
|
||||
pci_disable_msi(dev->pdev);
|
||||
if (pdev->msi_enabled)
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
pm_qos_remove_request(&dev_priv->pm_qos);
|
||||
i915_ggtt_cleanup_hw(dev_priv);
|
||||
@ -1133,7 +1121,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
|
||||
/* Reveal our presence to userspace */
|
||||
if (drm_dev_register(dev, 0) == 0) {
|
||||
i915_debugfs_register(dev_priv);
|
||||
i915_setup_sysfs(dev);
|
||||
i915_setup_sysfs(dev_priv);
|
||||
} else
|
||||
DRM_ERROR("Failed to register driver for userspace access!\n");
|
||||
|
||||
@ -1170,7 +1158,7 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
|
||||
acpi_video_unregister();
|
||||
intel_opregion_unregister(dev_priv);
|
||||
|
||||
i915_teardown_sysfs(&dev_priv->drm);
|
||||
i915_teardown_sysfs(dev_priv);
|
||||
i915_debugfs_unregister(dev_priv);
|
||||
drm_dev_unregister(&dev_priv->drm);
|
||||
|
||||
@ -1250,6 +1238,11 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
intel_runtime_pm_enable(dev_priv);
|
||||
|
||||
/* Everything is in place, we can now relax! */
|
||||
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
|
||||
driver.name, driver.major, driver.minor, driver.patchlevel,
|
||||
driver.date, pci_name(pdev), dev_priv->drm.primary->index);
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
|
||||
return 0;
|
||||
@ -1274,6 +1267,7 @@ out_free_priv:
|
||||
void i915_driver_unload(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
intel_fbdev_fini(dev);
|
||||
|
||||
@ -1302,8 +1296,8 @@ void i915_driver_unload(struct drm_device *dev)
|
||||
kfree(dev_priv->vbt.lfp_lvds_vbt_mode);
|
||||
dev_priv->vbt.lfp_lvds_vbt_mode = NULL;
|
||||
|
||||
vga_switcheroo_unregister_client(dev->pdev);
|
||||
vga_client_register(dev->pdev, NULL, NULL, NULL);
|
||||
vga_switcheroo_unregister_client(pdev);
|
||||
vga_client_register(pdev, NULL, NULL, NULL);
|
||||
|
||||
intel_csr_ucode_fini(dev_priv);
|
||||
|
||||
@ -1400,6 +1394,7 @@ static bool suspend_to_idle(struct drm_i915_private *dev_priv)
|
||||
static int i915_drm_suspend(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
pci_power_t opregion_target_state;
|
||||
int error;
|
||||
|
||||
@ -1416,11 +1411,11 @@ static int i915_drm_suspend(struct drm_device *dev)
|
||||
|
||||
drm_kms_helper_poll_disable(dev);
|
||||
|
||||
pci_save_state(dev->pdev);
|
||||
pci_save_state(pdev);
|
||||
|
||||
error = i915_gem_suspend(dev);
|
||||
if (error) {
|
||||
dev_err(&dev->pdev->dev,
|
||||
dev_err(&pdev->dev,
|
||||
"GEM idle failed, resume might fail\n");
|
||||
goto out;
|
||||
}
|
||||
@ -1462,9 +1457,10 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
|
||||
static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(drm_dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
bool fw_csr;
|
||||
int ret;
|
||||
|
||||
@ -1498,7 +1494,7 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pci_disable_device(drm_dev->pdev);
|
||||
pci_disable_device(pdev);
|
||||
/*
|
||||
* During hibernation on some platforms the BIOS may try to access
|
||||
* the device even though it's already in D3 and hang the machine. So
|
||||
@ -1512,7 +1508,7 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
|
||||
* Acer Aspire 1830T
|
||||
*/
|
||||
if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6))
|
||||
pci_set_power_state(drm_dev->pdev, PCI_D3hot);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
|
||||
dev_priv->suspended_to_idle = suspend_to_idle(dev_priv);
|
||||
|
||||
@ -1552,6 +1548,7 @@ static int i915_drm_resume(struct drm_device *dev)
|
||||
int ret;
|
||||
|
||||
disable_rpm_wakeref_asserts(dev_priv);
|
||||
intel_sanitize_gt_powersave(dev_priv);
|
||||
|
||||
ret = i915_ggtt_enable_hw(dev_priv);
|
||||
if (ret)
|
||||
@ -1581,7 +1578,7 @@ static int i915_drm_resume(struct drm_device *dev)
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (i915_gem_init_hw(dev)) {
|
||||
DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
|
||||
atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
|
||||
i915_gem_set_wedged(dev_priv);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
@ -1629,6 +1626,7 @@ static int i915_drm_resume(struct drm_device *dev)
|
||||
static int i915_drm_resume_early(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -1651,7 +1649,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
|
||||
* the device powered we can also remove the following set power state
|
||||
* call.
|
||||
*/
|
||||
ret = pci_set_power_state(dev->pdev, PCI_D0);
|
||||
ret = pci_set_power_state(pdev, PCI_D0);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to set PCI D0 power state (%d)\n", ret);
|
||||
goto out;
|
||||
@ -1670,12 +1668,12 @@ static int i915_drm_resume_early(struct drm_device *dev)
|
||||
* depend on the device enable refcount we can't anyway depend on them
|
||||
* disabling/enabling the device.
|
||||
*/
|
||||
if (pci_enable_device(dev->pdev)) {
|
||||
if (pci_enable_device(pdev)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pci_set_master(dev->pdev);
|
||||
pci_set_master(pdev);
|
||||
|
||||
disable_rpm_wakeref_asserts(dev_priv);
|
||||
|
||||
@ -1727,8 +1725,10 @@ int i915_resume_switcheroo(struct drm_device *dev)
|
||||
* i915_reset - reset chip after a hang
|
||||
* @dev: drm device to reset
|
||||
*
|
||||
* Reset the chip. Useful if a hang is detected. Returns zero on successful
|
||||
* reset or otherwise an error code.
|
||||
* Reset the chip. Useful if a hang is detected. Marks the device as wedged
|
||||
* on failure.
|
||||
*
|
||||
* Caller must hold the struct_mutex.
|
||||
*
|
||||
* Procedure is fairly simple:
|
||||
* - reset the chip using the reset reg
|
||||
@ -1738,29 +1738,22 @@ int i915_resume_switcheroo(struct drm_device *dev)
|
||||
* - re-init interrupt state
|
||||
* - re-init display
|
||||
*/
|
||||
int i915_reset(struct drm_i915_private *dev_priv)
|
||||
void i915_reset(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct i915_gpu_error *error = &dev_priv->gpu_error;
|
||||
unsigned reset_counter;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
lockdep_assert_held(&dev->struct_mutex);
|
||||
|
||||
if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags))
|
||||
return;
|
||||
|
||||
/* Clear any previous failed attempts at recovery. Time to try again. */
|
||||
atomic_andnot(I915_WEDGED, &error->reset_counter);
|
||||
|
||||
/* Clear the reset-in-progress flag and increment the reset epoch. */
|
||||
reset_counter = atomic_inc_return(&error->reset_counter);
|
||||
if (WARN_ON(__i915_reset_in_progress(reset_counter))) {
|
||||
ret = -EIO;
|
||||
goto error;
|
||||
}
|
||||
__clear_bit(I915_WEDGED, &error->flags);
|
||||
error->reset_count++;
|
||||
|
||||
pr_notice("drm/i915: Resetting chip after gpu hang\n");
|
||||
|
||||
i915_gem_reset(dev);
|
||||
|
||||
ret = intel_gpu_reset(dev_priv, ALL_ENGINES);
|
||||
if (ret) {
|
||||
if (ret != -ENODEV)
|
||||
@ -1770,6 +1763,7 @@ int i915_reset(struct drm_i915_private *dev_priv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
i915_gem_reset(dev_priv);
|
||||
intel_overlay_reset(dev_priv);
|
||||
|
||||
/* Ok, now get things going again... */
|
||||
@ -1792,43 +1786,43 @@ int i915_reset(struct drm_i915_private *dev_priv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
/*
|
||||
* rps/rc6 re-init is necessary to restore state lost after the
|
||||
* reset and the re-install of gt irqs. Skip for ironlake per
|
||||
* previous concerns that it doesn't respond well to some forms
|
||||
* of re-init after reset.
|
||||
*/
|
||||
intel_sanitize_gt_powersave(dev_priv);
|
||||
intel_autoenable_gt_powersave(dev_priv);
|
||||
|
||||
return 0;
|
||||
wakeup:
|
||||
wake_up_bit(&error->flags, I915_RESET_IN_PROGRESS);
|
||||
return;
|
||||
|
||||
error:
|
||||
atomic_or(I915_WEDGED, &error->reset_counter);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
i915_gem_set_wedged(dev_priv);
|
||||
goto wakeup;
|
||||
}
|
||||
|
||||
static int i915_pm_suspend(struct device *dev)
|
||||
static int i915_pm_suspend(struct device *kdev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct drm_device *drm_dev = pci_get_drvdata(pdev);
|
||||
struct pci_dev *pdev = to_pci_dev(kdev);
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
|
||||
if (!drm_dev) {
|
||||
dev_err(dev, "DRM not initialized, aborting suspend.\n");
|
||||
if (!dev) {
|
||||
dev_err(kdev, "DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
return i915_drm_suspend(drm_dev);
|
||||
return i915_drm_suspend(dev);
|
||||
}
|
||||
|
||||
static int i915_pm_suspend_late(struct device *dev)
|
||||
static int i915_pm_suspend_late(struct device *kdev)
|
||||
{
|
||||
struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
|
||||
struct drm_device *dev = &kdev_to_i915(kdev)->drm;
|
||||
|
||||
/*
|
||||
* We have a suspend ordering issue with the snd-hda driver also
|
||||
@ -1839,57 +1833,57 @@ static int i915_pm_suspend_late(struct device *dev)
|
||||
* FIXME: This should be solved with a special hdmi sink device or
|
||||
* similar so that power domains can be employed.
|
||||
*/
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
return i915_drm_suspend_late(drm_dev, false);
|
||||
return i915_drm_suspend_late(dev, false);
|
||||
}
|
||||
|
||||
static int i915_pm_poweroff_late(struct device *dev)
|
||||
static int i915_pm_poweroff_late(struct device *kdev)
|
||||
{
|
||||
struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
|
||||
struct drm_device *dev = &kdev_to_i915(kdev)->drm;
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
return i915_drm_suspend_late(drm_dev, true);
|
||||
return i915_drm_suspend_late(dev, true);
|
||||
}
|
||||
|
||||
static int i915_pm_resume_early(struct device *dev)
|
||||
static int i915_pm_resume_early(struct device *kdev)
|
||||
{
|
||||
struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
|
||||
struct drm_device *dev = &kdev_to_i915(kdev)->drm;
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
return i915_drm_resume_early(drm_dev);
|
||||
return i915_drm_resume_early(dev);
|
||||
}
|
||||
|
||||
static int i915_pm_resume(struct device *dev)
|
||||
static int i915_pm_resume(struct device *kdev)
|
||||
{
|
||||
struct drm_device *drm_dev = &dev_to_i915(dev)->drm;
|
||||
struct drm_device *dev = &kdev_to_i915(kdev)->drm;
|
||||
|
||||
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
return i915_drm_resume(drm_dev);
|
||||
return i915_drm_resume(dev);
|
||||
}
|
||||
|
||||
/* freeze: before creating the hibernation_image */
|
||||
static int i915_pm_freeze(struct device *dev)
|
||||
static int i915_pm_freeze(struct device *kdev)
|
||||
{
|
||||
return i915_pm_suspend(dev);
|
||||
return i915_pm_suspend(kdev);
|
||||
}
|
||||
|
||||
static int i915_pm_freeze_late(struct device *dev)
|
||||
static int i915_pm_freeze_late(struct device *kdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i915_pm_suspend_late(dev);
|
||||
ret = i915_pm_suspend_late(kdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_freeze_late(dev_to_i915(dev));
|
||||
ret = i915_gem_freeze_late(kdev_to_i915(kdev));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1897,25 +1891,25 @@ static int i915_pm_freeze_late(struct device *dev)
|
||||
}
|
||||
|
||||
/* thaw: called after creating the hibernation image, but before turning off. */
|
||||
static int i915_pm_thaw_early(struct device *dev)
|
||||
static int i915_pm_thaw_early(struct device *kdev)
|
||||
{
|
||||
return i915_pm_resume_early(dev);
|
||||
return i915_pm_resume_early(kdev);
|
||||
}
|
||||
|
||||
static int i915_pm_thaw(struct device *dev)
|
||||
static int i915_pm_thaw(struct device *kdev)
|
||||
{
|
||||
return i915_pm_resume(dev);
|
||||
return i915_pm_resume(kdev);
|
||||
}
|
||||
|
||||
/* restore: called after loading the hibernation image. */
|
||||
static int i915_pm_restore_early(struct device *dev)
|
||||
static int i915_pm_restore_early(struct device *kdev)
|
||||
{
|
||||
return i915_pm_resume_early(dev);
|
||||
return i915_pm_resume_early(kdev);
|
||||
}
|
||||
|
||||
static int i915_pm_restore(struct device *dev)
|
||||
static int i915_pm_restore(struct device *kdev)
|
||||
{
|
||||
return i915_pm_resume(dev);
|
||||
return i915_pm_resume(kdev);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2277,9 +2271,9 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_runtime_suspend(struct device *device)
|
||||
static int intel_runtime_suspend(struct device *kdev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct pci_dev *pdev = to_pci_dev(kdev);
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
int ret;
|
||||
@ -2305,7 +2299,7 @@ static int intel_runtime_suspend(struct device *device)
|
||||
* Bump the expiration timestamp, otherwise the suspend won't
|
||||
* be rescheduled.
|
||||
*/
|
||||
pm_runtime_mark_last_busy(device);
|
||||
pm_runtime_mark_last_busy(kdev);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -2384,9 +2378,9 @@ static int intel_runtime_suspend(struct device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_runtime_resume(struct device *device)
|
||||
static int intel_runtime_resume(struct device *kdev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct pci_dev *pdev = to_pci_dev(kdev);
|
||||
struct drm_device *dev = pci_get_drvdata(pdev);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
int ret = 0;
|
||||
|
@ -70,7 +70,7 @@
|
||||
|
||||
#define DRIVER_NAME "i915"
|
||||
#define DRIVER_DESC "Intel Graphics"
|
||||
#define DRIVER_DATE "20160822"
|
||||
#define DRIVER_DATE "20160919"
|
||||
|
||||
#undef WARN_ON
|
||||
/* Many gcc seem to no see through this and fall over :( */
|
||||
@ -510,8 +510,12 @@ struct drm_i915_display_funcs {
|
||||
struct intel_initial_plane_config *);
|
||||
int (*crtc_compute_clock)(struct intel_crtc *crtc,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
void (*crtc_enable)(struct drm_crtc *crtc);
|
||||
void (*crtc_disable)(struct drm_crtc *crtc);
|
||||
void (*crtc_enable)(struct intel_crtc_state *pipe_config,
|
||||
struct drm_atomic_state *old_state);
|
||||
void (*crtc_disable)(struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_atomic_state *old_state);
|
||||
void (*update_crtcs)(struct drm_atomic_state *state,
|
||||
unsigned int *crtc_vblank_mask);
|
||||
void (*audio_codec_enable)(struct drm_connector *connector,
|
||||
struct intel_encoder *encoder,
|
||||
const struct drm_display_mode *adjusted_mode);
|
||||
@ -575,8 +579,6 @@ struct intel_uncore_funcs {
|
||||
uint16_t val, bool trace);
|
||||
void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r,
|
||||
uint32_t val, bool trace);
|
||||
void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r,
|
||||
uint64_t val, bool trace);
|
||||
};
|
||||
|
||||
struct intel_uncore {
|
||||
@ -637,7 +639,7 @@ struct intel_csr {
|
||||
func(is_i915g) sep \
|
||||
func(is_i945gm) sep \
|
||||
func(is_g33) sep \
|
||||
func(need_gfx_hws) sep \
|
||||
func(hws_needs_physical) sep \
|
||||
func(is_g4x) sep \
|
||||
func(is_pineview) sep \
|
||||
func(is_broadwater) sep \
|
||||
@ -652,6 +654,19 @@ struct intel_csr {
|
||||
func(is_kabylake) sep \
|
||||
func(is_preliminary) sep \
|
||||
func(has_fbc) sep \
|
||||
func(has_psr) sep \
|
||||
func(has_runtime_pm) sep \
|
||||
func(has_csr) sep \
|
||||
func(has_resource_streamer) sep \
|
||||
func(has_rc6) sep \
|
||||
func(has_rc6p) sep \
|
||||
func(has_dp_mst) sep \
|
||||
func(has_gmbus_irq) sep \
|
||||
func(has_hw_contexts) sep \
|
||||
func(has_logical_ring_contexts) sep \
|
||||
func(has_l3_dpf) sep \
|
||||
func(has_gmch_display) sep \
|
||||
func(has_guc) sep \
|
||||
func(has_pipe_cxsr) sep \
|
||||
func(has_hotplug) sep \
|
||||
func(cursor_needs_physical) sep \
|
||||
@ -667,6 +682,24 @@ struct intel_csr {
|
||||
#define DEFINE_FLAG(name) u8 name:1
|
||||
#define SEP_SEMICOLON ;
|
||||
|
||||
struct sseu_dev_info {
|
||||
u8 slice_mask;
|
||||
u8 subslice_mask;
|
||||
u8 eu_total;
|
||||
u8 eu_per_subslice;
|
||||
u8 min_eu_in_pool;
|
||||
/* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
|
||||
u8 subslice_7eu[3];
|
||||
u8 has_slice_pg:1;
|
||||
u8 has_subslice_pg:1;
|
||||
u8 has_eu_pg:1;
|
||||
};
|
||||
|
||||
static inline unsigned int sseu_subslice_total(const struct sseu_dev_info *sseu)
|
||||
{
|
||||
return hweight8(sseu->slice_mask) * hweight8(sseu->subslice_mask);
|
||||
}
|
||||
|
||||
struct intel_device_info {
|
||||
u32 display_mmio_offset;
|
||||
u16 device_id;
|
||||
@ -677,6 +710,7 @@ struct intel_device_info {
|
||||
u8 ring_mask; /* Rings supported by the HW */
|
||||
u8 num_rings;
|
||||
DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
|
||||
u16 ddb_size; /* in blocks */
|
||||
/* Register offsets for the various display pipes and transcoders */
|
||||
int pipe_offsets[I915_MAX_TRANSCODERS];
|
||||
int trans_offsets[I915_MAX_TRANSCODERS];
|
||||
@ -684,17 +718,7 @@ struct intel_device_info {
|
||||
int cursor_offsets[I915_MAX_PIPES];
|
||||
|
||||
/* Slice/subslice/EU info */
|
||||
u8 slice_total;
|
||||
u8 subslice_total;
|
||||
u8 subslice_per_slice;
|
||||
u8 eu_total;
|
||||
u8 eu_per_subslice;
|
||||
u8 min_eu_in_pool;
|
||||
/* For each slice, which subslice(s) has(have) 7 EUs (bitfield)? */
|
||||
u8 subslice_7eu[3];
|
||||
u8 has_slice_pg:1;
|
||||
u8 has_subslice_pg:1;
|
||||
u8 has_eu_pg:1;
|
||||
struct sseu_dev_info sseu;
|
||||
|
||||
struct color_luts {
|
||||
u16 degamma_lut_size;
|
||||
@ -1161,6 +1185,7 @@ struct intel_gen6_power_mgmt {
|
||||
bool interrupts_enabled;
|
||||
u32 pm_iir;
|
||||
|
||||
/* PM interrupt bits that should never be masked */
|
||||
u32 pm_intr_keep;
|
||||
|
||||
/* Frequencies are stored in potentially platform dependent multiples.
|
||||
@ -1334,7 +1359,7 @@ struct i915_gem_mm {
|
||||
bool interruptible;
|
||||
|
||||
/* the indicator for dispatch video commands on two BSD rings */
|
||||
unsigned int bsd_engine_dispatch_index;
|
||||
atomic_t bsd_engine_dispatch_index;
|
||||
|
||||
/** Bit 6 swizzling required for X tiling */
|
||||
uint32_t bit_6_swizzle_x;
|
||||
@ -1382,9 +1407,10 @@ struct i915_gpu_error {
|
||||
* State variable controlling the reset flow and count
|
||||
*
|
||||
* This is a counter which gets incremented when reset is triggered,
|
||||
* and again when reset has been handled. So odd values (lowest bit set)
|
||||
* means that reset is in progress and even values that
|
||||
* (reset_counter >> 1):th reset was successfully completed.
|
||||
*
|
||||
* Before the reset commences, the I915_RESET_IN_PROGRESS bit is set
|
||||
* meaning that any waiters holding onto the struct_mutex should
|
||||
* relinquish the lock immediately in order for the reset to start.
|
||||
*
|
||||
* If reset is not completed succesfully, the I915_WEDGE bit is
|
||||
* set meaning that hardware is terminally sour and there is no
|
||||
@ -1399,10 +1425,11 @@ struct i915_gpu_error {
|
||||
* naturally enforces the correct ordering between the bail-out of the
|
||||
* waiter and the gpu reset work code.
|
||||
*/
|
||||
atomic_t reset_counter;
|
||||
unsigned long reset_count;
|
||||
|
||||
#define I915_RESET_IN_PROGRESS_FLAG 1
|
||||
#define I915_WEDGED (1 << 31)
|
||||
unsigned long flags;
|
||||
#define I915_RESET_IN_PROGRESS 0
|
||||
#define I915_WEDGED (BITS_PER_LONG - 1)
|
||||
|
||||
/**
|
||||
* Waitqueue to signal when a hang is detected. Used to for waiters
|
||||
@ -1956,6 +1983,13 @@ struct drm_i915_private {
|
||||
struct i915_suspend_saved_registers regfile;
|
||||
struct vlv_s0ix_state vlv_s0ix_state;
|
||||
|
||||
enum {
|
||||
I915_SKL_SAGV_UNKNOWN = 0,
|
||||
I915_SKL_SAGV_DISABLED,
|
||||
I915_SKL_SAGV_ENABLED,
|
||||
I915_SKL_SAGV_NOT_CONTROLLED
|
||||
} skl_sagv_status;
|
||||
|
||||
struct {
|
||||
/*
|
||||
* Raw watermark latency values:
|
||||
@ -2010,6 +2044,7 @@ struct drm_i915_private {
|
||||
|
||||
/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
|
||||
struct {
|
||||
void (*resume)(struct drm_i915_private *);
|
||||
void (*cleanup_engine)(struct intel_engine_cs *engine);
|
||||
|
||||
/**
|
||||
@ -2057,9 +2092,9 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
|
||||
return container_of(dev, struct drm_i915_private, drm);
|
||||
}
|
||||
|
||||
static inline struct drm_i915_private *dev_to_i915(struct device *dev)
|
||||
static inline struct drm_i915_private *kdev_to_i915(struct device *kdev)
|
||||
{
|
||||
return to_i915(dev_get_drvdata(dev));
|
||||
return to_i915(dev_get_drvdata(kdev));
|
||||
}
|
||||
|
||||
static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
|
||||
@ -2082,13 +2117,16 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
|
||||
for_each_if (((id__) = (engine__)->id, \
|
||||
intel_engine_initialized(engine__)))
|
||||
|
||||
#define __mask_next_bit(mask) ({ \
|
||||
int __idx = ffs(mask) - 1; \
|
||||
mask &= ~BIT(__idx); \
|
||||
__idx; \
|
||||
})
|
||||
|
||||
/* Iterator over subset of engines selected by mask */
|
||||
#define for_each_engine_masked(engine__, dev_priv__, mask__) \
|
||||
for ((engine__) = &(dev_priv__)->engine[0]; \
|
||||
(engine__) < &(dev_priv__)->engine[I915_NUM_ENGINES]; \
|
||||
(engine__)++) \
|
||||
for_each_if (((mask__) & intel_engine_flag(engine__)) && \
|
||||
intel_engine_initialized(engine__))
|
||||
#define for_each_engine_masked(engine__, dev_priv__, mask__, tmp__) \
|
||||
for (tmp__ = mask__ & INTEL_INFO(dev_priv__)->ring_mask; \
|
||||
tmp__ ? (engine__ = &(dev_priv__)->engine[__mask_next_bit(tmp__)]), 1 : 0; )
|
||||
|
||||
enum hdmi_force_audio {
|
||||
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
|
||||
@ -2549,7 +2587,7 @@ struct drm_i915_cmd_table {
|
||||
BUILD_BUG(); \
|
||||
__p; \
|
||||
})
|
||||
#define INTEL_INFO(p) (&__I915__(p)->info)
|
||||
#define INTEL_INFO(p) (&__I915__(p)->info)
|
||||
#define INTEL_GEN(p) (INTEL_INFO(p)->gen)
|
||||
#define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
|
||||
|
||||
@ -2716,10 +2754,10 @@ struct drm_i915_cmd_table {
|
||||
#define HAS_EDRAM(dev) (!!(__I915__(dev)->edram_cap & EDRAM_ENABLED))
|
||||
#define HAS_WT(dev) ((IS_HASWELL(dev) || IS_BROADWELL(dev)) && \
|
||||
HAS_EDRAM(dev))
|
||||
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
|
||||
#define HWS_NEEDS_PHYSICAL(dev) (INTEL_INFO(dev)->hws_needs_physical)
|
||||
|
||||
#define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 6)
|
||||
#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8)
|
||||
#define HAS_HW_CONTEXTS(dev) (INTEL_INFO(dev)->has_hw_contexts)
|
||||
#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->has_logical_ring_contexts)
|
||||
#define USES_PPGTT(dev) (i915.enable_ppgtt)
|
||||
#define USES_FULL_PPGTT(dev) (i915.enable_ppgtt >= 2)
|
||||
#define USES_FULL_48BIT_PPGTT(dev) (i915.enable_ppgtt == 3)
|
||||
@ -2743,7 +2781,7 @@ struct drm_i915_cmd_table {
|
||||
* interrupt source and so prevents the other device from working properly.
|
||||
*/
|
||||
#define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
|
||||
#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
|
||||
#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->has_gmbus_irq)
|
||||
|
||||
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
|
||||
* rows, which changed the alignment requirements and fence programming.
|
||||
@ -2759,38 +2797,27 @@ struct drm_i915_cmd_table {
|
||||
|
||||
#define HAS_IPS(dev) (IS_HSW_ULT(dev) || IS_BROADWELL(dev))
|
||||
|
||||
#define HAS_DP_MST(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
|
||||
INTEL_INFO(dev)->gen >= 9)
|
||||
#define HAS_DP_MST(dev) (INTEL_INFO(dev)->has_dp_mst)
|
||||
|
||||
#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi)
|
||||
#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg)
|
||||
#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
|
||||
IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
|
||||
IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
|
||||
#define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \
|
||||
IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \
|
||||
IS_CHERRYVIEW(dev) || IS_SKYLAKE(dev) || \
|
||||
IS_KABYLAKE(dev) || IS_BROXTON(dev))
|
||||
#define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6)
|
||||
#define HAS_RC6p(dev) (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
|
||||
#define HAS_PSR(dev) (INTEL_INFO(dev)->has_psr)
|
||||
#define HAS_RUNTIME_PM(dev) (INTEL_INFO(dev)->has_runtime_pm)
|
||||
#define HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
|
||||
#define HAS_RC6p(dev) (INTEL_INFO(dev)->has_rc6p)
|
||||
|
||||
#define HAS_CSR(dev) (IS_GEN9(dev))
|
||||
#define HAS_CSR(dev) (INTEL_INFO(dev)->has_csr)
|
||||
|
||||
/*
|
||||
* For now, anything with a GuC requires uCode loading, and then supports
|
||||
* command submission once loaded. But these are logically independent
|
||||
* properties, so we have separate macros to test them.
|
||||
*/
|
||||
#define HAS_GUC(dev) (IS_GEN9(dev))
|
||||
#define HAS_GUC(dev) (INTEL_INFO(dev)->has_guc)
|
||||
#define HAS_GUC_UCODE(dev) (HAS_GUC(dev))
|
||||
#define HAS_GUC_SCHED(dev) (HAS_GUC(dev))
|
||||
|
||||
#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \
|
||||
INTEL_INFO(dev)->gen >= 8)
|
||||
|
||||
#define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \
|
||||
!IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) && \
|
||||
!IS_BROXTON(dev))
|
||||
#define HAS_RESOURCE_STREAMER(dev) (INTEL_INFO(dev)->has_resource_streamer)
|
||||
|
||||
#define HAS_POOLED_EU(dev) (INTEL_INFO(dev)->has_pooled_eu)
|
||||
|
||||
@ -2818,11 +2845,10 @@ struct drm_i915_cmd_table {
|
||||
#define HAS_PCH_NOP(dev) (INTEL_PCH_TYPE(dev) == PCH_NOP)
|
||||
#define HAS_PCH_SPLIT(dev) (INTEL_PCH_TYPE(dev) != PCH_NONE)
|
||||
|
||||
#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->gen < 5 || \
|
||||
IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
#define HAS_GMCH_DISPLAY(dev) (INTEL_INFO(dev)->has_gmch_display)
|
||||
|
||||
/* DPF == dynamic parity feature */
|
||||
#define HAS_L3_DPF(dev) (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
|
||||
#define HAS_L3_DPF(dev) (INTEL_INFO(dev)->has_l3_dpf)
|
||||
#define NUM_L3_SLICES(dev) (IS_HSW_GT3(dev) ? 2 : HAS_L3_DPF(dev))
|
||||
|
||||
#define GT_FREQUENCY_MULTIPLIER 50
|
||||
@ -2843,7 +2869,7 @@ extern int i915_suspend_switcheroo(struct drm_device *dev, pm_message_t state);
|
||||
extern int i915_resume_switcheroo(struct drm_device *dev);
|
||||
|
||||
int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
|
||||
int enable_ppgtt);
|
||||
int enable_ppgtt);
|
||||
|
||||
bool intel_sanitize_semaphores(struct drm_i915_private *dev_priv, int value);
|
||||
|
||||
@ -2861,7 +2887,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
#endif
|
||||
extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask);
|
||||
extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv);
|
||||
extern int i915_reset(struct drm_i915_private *dev_priv);
|
||||
extern void i915_reset(struct drm_i915_private *dev_priv);
|
||||
extern int intel_guc_reset(struct drm_i915_private *dev_priv);
|
||||
extern void intel_engine_init_hangcheck(struct intel_engine_cs *engine);
|
||||
extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
|
||||
@ -3197,8 +3223,6 @@ i915_gem_obj_finish_shmem_access(struct drm_i915_gem_object *obj)
|
||||
}
|
||||
|
||||
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
|
||||
int i915_gem_object_sync(struct drm_i915_gem_object *obj,
|
||||
struct drm_i915_gem_request *to);
|
||||
void i915_vma_move_to_active(struct i915_vma *vma,
|
||||
struct drm_i915_gem_request *req,
|
||||
unsigned int flags);
|
||||
@ -3207,6 +3231,7 @@ int i915_gem_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset);
|
||||
int i915_gem_mmap_gtt_version(void);
|
||||
|
||||
void i915_gem_track_fb(struct drm_i915_gem_object *old,
|
||||
struct drm_i915_gem_object *new,
|
||||
@ -3219,54 +3244,35 @@ i915_gem_find_active_request(struct intel_engine_cs *engine);
|
||||
|
||||
void i915_gem_retire_requests(struct drm_i915_private *dev_priv);
|
||||
|
||||
static inline u32 i915_reset_counter(struct i915_gpu_error *error)
|
||||
{
|
||||
return atomic_read(&error->reset_counter);
|
||||
}
|
||||
|
||||
static inline bool __i915_reset_in_progress(u32 reset)
|
||||
{
|
||||
return unlikely(reset & I915_RESET_IN_PROGRESS_FLAG);
|
||||
}
|
||||
|
||||
static inline bool __i915_reset_in_progress_or_wedged(u32 reset)
|
||||
{
|
||||
return unlikely(reset & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED));
|
||||
}
|
||||
|
||||
static inline bool __i915_terminally_wedged(u32 reset)
|
||||
{
|
||||
return unlikely(reset & I915_WEDGED);
|
||||
}
|
||||
|
||||
static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
|
||||
{
|
||||
return __i915_reset_in_progress(i915_reset_counter(error));
|
||||
}
|
||||
|
||||
static inline bool i915_reset_in_progress_or_wedged(struct i915_gpu_error *error)
|
||||
{
|
||||
return __i915_reset_in_progress_or_wedged(i915_reset_counter(error));
|
||||
return unlikely(test_bit(I915_RESET_IN_PROGRESS, &error->flags));
|
||||
}
|
||||
|
||||
static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
|
||||
{
|
||||
return __i915_terminally_wedged(i915_reset_counter(error));
|
||||
return unlikely(test_bit(I915_WEDGED, &error->flags));
|
||||
}
|
||||
|
||||
static inline bool i915_reset_in_progress_or_wedged(struct i915_gpu_error *error)
|
||||
{
|
||||
return i915_reset_in_progress(error) | i915_terminally_wedged(error);
|
||||
}
|
||||
|
||||
static inline u32 i915_reset_count(struct i915_gpu_error *error)
|
||||
{
|
||||
return ((i915_reset_counter(error) & ~I915_WEDGED) + 1) / 2;
|
||||
return READ_ONCE(error->reset_count);
|
||||
}
|
||||
|
||||
void i915_gem_reset(struct drm_device *dev);
|
||||
void i915_gem_reset(struct drm_i915_private *dev_priv);
|
||||
void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
|
||||
bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
|
||||
int __must_check i915_gem_init(struct drm_device *dev);
|
||||
int __must_check i915_gem_init_hw(struct drm_device *dev);
|
||||
void i915_gem_init_swizzling(struct drm_device *dev);
|
||||
void i915_gem_cleanup_engines(struct drm_device *dev);
|
||||
int __must_check i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
|
||||
bool interruptible);
|
||||
unsigned int flags);
|
||||
int __must_check i915_gem_suspend(struct drm_device *dev);
|
||||
void i915_gem_resume(struct drm_device *dev);
|
||||
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
@ -3388,7 +3394,6 @@ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
|
||||
int __must_check i915_gem_context_init(struct drm_device *dev);
|
||||
void i915_gem_context_lost(struct drm_i915_private *dev_priv);
|
||||
void i915_gem_context_fini(struct drm_device *dev);
|
||||
void i915_gem_context_reset(struct drm_device *dev);
|
||||
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
|
||||
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
|
||||
int i915_switch_context(struct drm_i915_gem_request *req);
|
||||
@ -3507,13 +3512,13 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec
|
||||
int i915_debugfs_register(struct drm_i915_private *dev_priv);
|
||||
void i915_debugfs_unregister(struct drm_i915_private *dev_priv);
|
||||
int i915_debugfs_connector_add(struct drm_connector *connector);
|
||||
void intel_display_crc_init(struct drm_device *dev);
|
||||
void intel_display_crc_init(struct drm_i915_private *dev_priv);
|
||||
#else
|
||||
static inline int i915_debugfs_register(struct drm_i915_private *dev_priv) {return 0;}
|
||||
static inline void i915_debugfs_unregister(struct drm_i915_private *dev_priv) {}
|
||||
static inline int i915_debugfs_connector_add(struct drm_connector *connector)
|
||||
{ return 0; }
|
||||
static inline void intel_display_crc_init(struct drm_device *dev) {}
|
||||
static inline void intel_display_crc_init(struct drm_i915_private *dev_priv) {}
|
||||
#endif
|
||||
|
||||
/* i915_gpu_error.c */
|
||||
@ -3557,8 +3562,8 @@ extern int i915_save_state(struct drm_device *dev);
|
||||
extern int i915_restore_state(struct drm_device *dev);
|
||||
|
||||
/* i915_sysfs.c */
|
||||
void i915_setup_sysfs(struct drm_device *dev_priv);
|
||||
void i915_teardown_sysfs(struct drm_device *dev_priv);
|
||||
void i915_setup_sysfs(struct drm_i915_private *dev_priv);
|
||||
void i915_teardown_sysfs(struct drm_i915_private *dev_priv);
|
||||
|
||||
/* intel_i2c.c */
|
||||
extern int intel_setup_gmbus(struct drm_device *dev);
|
||||
@ -3735,9 +3740,16 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
|
||||
* will be implemented using 2 32-bit writes in an arbitrary order with
|
||||
* an arbitrary delay between them. This can cause the hardware to
|
||||
* act upon the intermediate value, possibly leading to corruption and
|
||||
* machine death. You have been warned.
|
||||
* machine death. For this reason we do not support I915_WRITE64, or
|
||||
* dev_priv->uncore.funcs.mmio_writeq.
|
||||
*
|
||||
* When reading a 64-bit value as two 32-bit values, the delay may cause
|
||||
* the two reads to mismatch, e.g. a timestamp overflowing. Also note that
|
||||
* occasionally a 64-bit register does not actualy support a full readq
|
||||
* and must be read using two 32-bit reads.
|
||||
*
|
||||
* You have been warned.
|
||||
*/
|
||||
#define I915_WRITE64(reg, val) dev_priv->uncore.funcs.mmio_writeq(dev_priv, (reg), (val), true)
|
||||
#define I915_READ64(reg) dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
|
||||
|
||||
#define I915_READ64_2x32(lower_reg, upper_reg) ({ \
|
||||
@ -3780,7 +3792,7 @@ __raw_write(64, q)
|
||||
#undef __raw_write
|
||||
|
||||
/* These are untraced mmio-accessors that are only valid to be used inside
|
||||
* criticial sections inside IRQ handlers where forcewake is explicitly
|
||||
* critical sections inside IRQ handlers where forcewake is explicitly
|
||||
* controlled.
|
||||
* Think twice, and think again, before using these.
|
||||
* Note: Should only be used between intel_uncore_forcewake_irqlock() and
|
||||
@ -3852,7 +3864,9 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
|
||||
schedule_timeout_uninterruptible(remaining_jiffies);
|
||||
}
|
||||
}
|
||||
static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
|
||||
|
||||
static inline bool
|
||||
__i915_request_irq_complete(struct drm_i915_gem_request *req)
|
||||
{
|
||||
struct intel_engine_cs *engine = req->engine;
|
||||
|
||||
@ -3914,17 +3928,6 @@ static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We need to check whether any gpu reset happened in between
|
||||
* the request being submitted and now. If a reset has occurred,
|
||||
* the seqno will have been advance past ours and our request
|
||||
* is complete. If we are in the process of handling a reset,
|
||||
* the request is effectively complete as the rendering will
|
||||
* be discarded, but we need to return in order to drop the
|
||||
* struct_mutex.
|
||||
*/
|
||||
if (i915_reset_in_progress(&req->i915->gpu_error))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -386,7 +386,8 @@ __unsafe_wait_rendering(struct drm_i915_gem_object *obj,
|
||||
int ret;
|
||||
|
||||
ret = i915_gem_active_wait_unlocked(&active[idx],
|
||||
true, NULL, rps);
|
||||
I915_WAIT_INTERRUPTIBLE,
|
||||
NULL, rps);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -1679,6 +1680,56 @@ static unsigned int tile_row_pages(struct drm_i915_gem_object *obj)
|
||||
return size >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_mmap_gtt_version - report the current feature set for GTT mmaps
|
||||
*
|
||||
* A history of the GTT mmap interface:
|
||||
*
|
||||
* 0 - Everything had to fit into the GTT. Both parties of a memcpy had to
|
||||
* aligned and suitable for fencing, and still fit into the available
|
||||
* mappable space left by the pinned display objects. A classic problem
|
||||
* we called the page-fault-of-doom where we would ping-pong between
|
||||
* two objects that could not fit inside the GTT and so the memcpy
|
||||
* would page one object in at the expense of the other between every
|
||||
* single byte.
|
||||
*
|
||||
* 1 - Objects can be any size, and have any compatible fencing (X Y, or none
|
||||
* as set via i915_gem_set_tiling() [DRM_I915_GEM_SET_TILING]). If the
|
||||
* object is too large for the available space (or simply too large
|
||||
* for the mappable aperture!), a view is created instead and faulted
|
||||
* into userspace. (This view is aligned and sized appropriately for
|
||||
* fenced access.)
|
||||
*
|
||||
* Restrictions:
|
||||
*
|
||||
* * snoopable objects cannot be accessed via the GTT. It can cause machine
|
||||
* hangs on some architectures, corruption on others. An attempt to service
|
||||
* a GTT page fault from a snoopable object will generate a SIGBUS.
|
||||
*
|
||||
* * the object must be able to fit into RAM (physical memory, though no
|
||||
* limited to the mappable aperture).
|
||||
*
|
||||
*
|
||||
* Caveats:
|
||||
*
|
||||
* * a new GTT page fault will synchronize rendering from the GPU and flush
|
||||
* all data to system memory. Subsequent access will not be synchronized.
|
||||
*
|
||||
* * all mappings are revoked on runtime device suspend.
|
||||
*
|
||||
* * there are only 8, 16 or 32 fence registers to share between all users
|
||||
* (older machines require fence register for display and blitter access
|
||||
* as well). Contention of the fence registers will cause the previous users
|
||||
* to be unmapped and any new access will generate new page faults.
|
||||
*
|
||||
* * running out of memory while servicing a fault may generate a SIGBUS,
|
||||
* rather than the expected SIGSEGV.
|
||||
*/
|
||||
int i915_gem_mmap_gtt_version(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_fault - fault a page into the GTT
|
||||
* @area: CPU VMA in question
|
||||
@ -1694,6 +1745,9 @@ static unsigned int tile_row_pages(struct drm_i915_gem_object *obj)
|
||||
* from the GTT and/or fence registers to make room. So performance may
|
||||
* suffer if the GTT working set is large or there are few fence registers
|
||||
* left.
|
||||
*
|
||||
* The current feature set supported by i915_gem_fault() and thus GTT mmaps
|
||||
* is exposed via I915_PARAM_MMAP_GTT_VERSION (see i915_gem_mmap_gtt_version).
|
||||
*/
|
||||
int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf)
|
||||
{
|
||||
@ -1973,7 +2027,7 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
|
||||
* to claim that space for ourselves, we need to take the big
|
||||
* struct_mutex to free the requests+objects and allocate our slot.
|
||||
*/
|
||||
err = i915_gem_wait_for_idle(dev_priv, true);
|
||||
err = i915_gem_wait_for_idle(dev_priv, I915_WAIT_INTERRUPTIBLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2495,32 +2549,94 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
|
||||
if (i915_gem_request_completed(request))
|
||||
continue;
|
||||
|
||||
if (!i915_sw_fence_done(&request->submit))
|
||||
break;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void i915_gem_reset_engine_status(struct intel_engine_cs *engine)
|
||||
static void reset_request(struct drm_i915_gem_request *request)
|
||||
{
|
||||
void *vaddr = request->ring->vaddr;
|
||||
u32 head;
|
||||
|
||||
/* As this request likely depends on state from the lost
|
||||
* context, clear out all the user operations leaving the
|
||||
* breadcrumb at the end (so we get the fence notifications).
|
||||
*/
|
||||
head = request->head;
|
||||
if (request->postfix < head) {
|
||||
memset(vaddr + head, 0, request->ring->size - head);
|
||||
head = 0;
|
||||
}
|
||||
memset(vaddr + head, 0, request->postfix - head);
|
||||
}
|
||||
|
||||
static void i915_gem_reset_engine(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct i915_gem_context *incomplete_ctx;
|
||||
bool ring_hung;
|
||||
|
||||
/* Ensure irq handler finishes, and not run again. */
|
||||
tasklet_kill(&engine->irq_tasklet);
|
||||
if (engine->irq_seqno_barrier)
|
||||
engine->irq_seqno_barrier(engine);
|
||||
|
||||
request = i915_gem_find_active_request(engine);
|
||||
if (request == NULL)
|
||||
if (!request)
|
||||
return;
|
||||
|
||||
ring_hung = engine->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
|
||||
|
||||
i915_set_reset_status(request->ctx, ring_hung);
|
||||
if (!ring_hung)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_DRIVER("resetting %s to restart from tail of request 0x%x\n",
|
||||
engine->name, request->fence.seqno);
|
||||
|
||||
/* Setup the CS to resume from the breadcrumb of the hung request */
|
||||
engine->reset_hw(engine, request);
|
||||
|
||||
/* Users of the default context do not rely on logical state
|
||||
* preserved between batches. They have to emit full state on
|
||||
* every batch and so it is safe to execute queued requests following
|
||||
* the hang.
|
||||
*
|
||||
* Other contexts preserve state, now corrupt. We want to skip all
|
||||
* queued requests that reference the corrupt context.
|
||||
*/
|
||||
incomplete_ctx = request->ctx;
|
||||
if (i915_gem_context_is_default(incomplete_ctx))
|
||||
return;
|
||||
|
||||
list_for_each_entry_continue(request, &engine->request_list, link)
|
||||
i915_set_reset_status(request->ctx, false);
|
||||
if (request->ctx == incomplete_ctx)
|
||||
reset_request(request);
|
||||
}
|
||||
|
||||
static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
|
||||
void i915_gem_reset(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_i915_gem_request *request;
|
||||
struct intel_ring *ring;
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
|
||||
for_each_engine(engine, dev_priv)
|
||||
i915_gem_reset_engine(engine);
|
||||
|
||||
i915_gem_restore_fences(&dev_priv->drm);
|
||||
}
|
||||
|
||||
static void nop_submit_request(struct drm_i915_gem_request *request)
|
||||
{
|
||||
}
|
||||
|
||||
static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
|
||||
{
|
||||
engine->submit_request = nop_submit_request;
|
||||
|
||||
/* Mark all pending requests as complete so that any concurrent
|
||||
* (lockless) lookup doesn't try and wait upon the request as we
|
||||
@ -2535,60 +2651,30 @@ static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
|
||||
*/
|
||||
|
||||
if (i915.enable_execlists) {
|
||||
/* Ensure irq handler finishes or is cancelled. */
|
||||
tasklet_kill(&engine->irq_tasklet);
|
||||
|
||||
intel_execlists_cancel_requests(engine);
|
||||
}
|
||||
|
||||
/*
|
||||
* We must free the requests after all the corresponding objects have
|
||||
* been moved off active lists. Which is the same order as the normal
|
||||
* retire_requests function does. This is important if object hold
|
||||
* implicit references on things like e.g. ppgtt address spaces through
|
||||
* the request.
|
||||
*/
|
||||
request = i915_gem_active_raw(&engine->last_request,
|
||||
&engine->i915->drm.struct_mutex);
|
||||
if (request)
|
||||
i915_gem_request_retire_upto(request);
|
||||
GEM_BUG_ON(intel_engine_is_active(engine));
|
||||
|
||||
/* Having flushed all requests from all queues, we know that all
|
||||
* ringbuffers must now be empty. However, since we do not reclaim
|
||||
* all space when retiring the request (to prevent HEADs colliding
|
||||
* with rapid ringbuffer wraparound) the amount of available space
|
||||
* upon reset is less than when we start. Do one more pass over
|
||||
* all the ringbuffers to reset last_retired_head.
|
||||
*/
|
||||
list_for_each_entry(ring, &engine->buffers, link) {
|
||||
ring->last_retired_head = ring->tail;
|
||||
intel_ring_update_space(ring);
|
||||
spin_lock(&engine->execlist_lock);
|
||||
INIT_LIST_HEAD(&engine->execlist_queue);
|
||||
i915_gem_request_put(engine->execlist_port[0].request);
|
||||
i915_gem_request_put(engine->execlist_port[1].request);
|
||||
memset(engine->execlist_port, 0, sizeof(engine->execlist_port));
|
||||
spin_unlock(&engine->execlist_lock);
|
||||
}
|
||||
|
||||
engine->i915->gt.active_engines &= ~intel_engine_flag(engine);
|
||||
}
|
||||
|
||||
void i915_gem_reset(struct drm_device *dev)
|
||||
void i915_gem_set_wedged(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
/*
|
||||
* Before we free the objects from the requests, we need to inspect
|
||||
* them for finding the guilty party. As the requests only borrow
|
||||
* their reference to the objects, the inspection must be done first.
|
||||
*/
|
||||
for_each_engine(engine, dev_priv)
|
||||
i915_gem_reset_engine_status(engine);
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
set_bit(I915_WEDGED, &dev_priv->gpu_error.flags);
|
||||
|
||||
i915_gem_context_lost(dev_priv);
|
||||
for_each_engine(engine, dev_priv)
|
||||
i915_gem_reset_engine_cleanup(engine);
|
||||
i915_gem_cleanup_engine(engine);
|
||||
mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0);
|
||||
|
||||
i915_gem_context_reset(dev);
|
||||
|
||||
i915_gem_restore_fences(dev);
|
||||
i915_gem_retire_requests(dev_priv);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2721,7 +2807,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
active = __I915_BO_ACTIVE(obj);
|
||||
for_each_active(active, idx) {
|
||||
s64 *timeout = args->timeout_ns >= 0 ? &args->timeout_ns : NULL;
|
||||
ret = i915_gem_active_wait_unlocked(&obj->last_read[idx], true,
|
||||
ret = i915_gem_active_wait_unlocked(&obj->last_read[idx],
|
||||
I915_WAIT_INTERRUPTIBLE,
|
||||
timeout, rps);
|
||||
if (ret)
|
||||
break;
|
||||
@ -2731,96 +2818,6 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
__i915_gem_object_sync(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_request *from)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (to->engine == from->engine)
|
||||
return 0;
|
||||
|
||||
if (!i915.semaphores) {
|
||||
ret = i915_wait_request(from,
|
||||
from->i915->mm.interruptible,
|
||||
NULL,
|
||||
NO_WAITBOOST);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
int idx = intel_engine_sync_index(from->engine, to->engine);
|
||||
if (from->fence.seqno <= from->engine->semaphore.sync_seqno[idx])
|
||||
return 0;
|
||||
|
||||
trace_i915_gem_ring_sync_to(to, from);
|
||||
ret = to->engine->semaphore.sync_to(to, from);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
from->engine->semaphore.sync_seqno[idx] = from->fence.seqno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_object_sync - sync an object to a ring.
|
||||
*
|
||||
* @obj: object which may be in use on another ring.
|
||||
* @to: request we are wishing to use
|
||||
*
|
||||
* This code is meant to abstract object synchronization with the GPU.
|
||||
* Conceptually we serialise writes between engines inside the GPU.
|
||||
* We only allow one engine to write into a buffer at any time, but
|
||||
* multiple readers. To ensure each has a coherent view of memory, we must:
|
||||
*
|
||||
* - If there is an outstanding write request to the object, the new
|
||||
* request must wait for it to complete (either CPU or in hw, requests
|
||||
* on the same ring will be naturally ordered).
|
||||
*
|
||||
* - If we are a write request (pending_write_domain is set), the new
|
||||
* request must wait for outstanding read requests to complete.
|
||||
*
|
||||
* Returns 0 if successful, else propagates up the lower layer error.
|
||||
*/
|
||||
int
|
||||
i915_gem_object_sync(struct drm_i915_gem_object *obj,
|
||||
struct drm_i915_gem_request *to)
|
||||
{
|
||||
struct i915_gem_active *active;
|
||||
unsigned long active_mask;
|
||||
int idx;
|
||||
|
||||
lockdep_assert_held(&obj->base.dev->struct_mutex);
|
||||
|
||||
active_mask = i915_gem_object_get_active(obj);
|
||||
if (!active_mask)
|
||||
return 0;
|
||||
|
||||
if (obj->base.pending_write_domain) {
|
||||
active = obj->last_read;
|
||||
} else {
|
||||
active_mask = 1;
|
||||
active = &obj->last_write;
|
||||
}
|
||||
|
||||
for_each_active(active_mask, idx) {
|
||||
struct drm_i915_gem_request *request;
|
||||
int ret;
|
||||
|
||||
request = i915_gem_active_peek(&active[idx],
|
||||
&obj->base.dev->struct_mutex);
|
||||
if (!request)
|
||||
continue;
|
||||
|
||||
ret = __i915_gem_object_sync(to, request);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __i915_vma_iounmap(struct i915_vma *vma)
|
||||
{
|
||||
GEM_BUG_ON(i915_vma_is_pinned(vma));
|
||||
@ -2924,7 +2921,7 @@ destroy:
|
||||
}
|
||||
|
||||
int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
|
||||
bool interruptible)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
int ret;
|
||||
@ -2933,7 +2930,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
|
||||
if (engine->last_context == NULL)
|
||||
continue;
|
||||
|
||||
ret = intel_engine_idle(engine, interruptible);
|
||||
ret = intel_engine_idle(engine, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -3688,7 +3685,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
|
||||
if (target == NULL)
|
||||
return 0;
|
||||
|
||||
ret = i915_wait_request(target, true, NULL, NULL);
|
||||
ret = i915_wait_request(target, I915_WAIT_INTERRUPTIBLE, NULL, NULL);
|
||||
i915_gem_request_put(target);
|
||||
|
||||
return ret;
|
||||
@ -4244,7 +4241,9 @@ int i915_gem_suspend(struct drm_device *dev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = i915_gem_wait_for_idle(dev_priv, true);
|
||||
ret = i915_gem_wait_for_idle(dev_priv,
|
||||
I915_WAIT_INTERRUPTIBLE |
|
||||
I915_WAIT_LOCKED);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@ -4280,8 +4279,7 @@ void i915_gem_resume(struct drm_device *dev)
|
||||
* guarantee that the context image is complete. So let's just reset
|
||||
* it and start again.
|
||||
*/
|
||||
if (i915.enable_execlists)
|
||||
intel_lr_context_reset(dev_priv, dev_priv->kernel_context);
|
||||
dev_priv->gt.resume(dev_priv);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
@ -4433,8 +4431,10 @@ int i915_gem_init(struct drm_device *dev)
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (!i915.enable_execlists) {
|
||||
dev_priv->gt.resume = intel_legacy_submission_resume;
|
||||
dev_priv->gt.cleanup_engine = intel_engine_cleanup;
|
||||
} else {
|
||||
dev_priv->gt.resume = intel_lr_context_resume;
|
||||
dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
|
||||
}
|
||||
|
||||
@ -4467,7 +4467,7 @@ int i915_gem_init(struct drm_device *dev)
|
||||
* for all other failure, such as an allocation failure, bail.
|
||||
*/
|
||||
DRM_ERROR("Failed to initialize GPU, declaring it wedged\n");
|
||||
atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
|
||||
i915_gem_set_wedged(dev_priv);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@ -4569,6 +4569,8 @@ i915_gem_load_init(struct drm_device *dev)
|
||||
|
||||
dev_priv->mm.interruptible = true;
|
||||
|
||||
atomic_set(&dev_priv->mm.bsd_engine_dispatch_index, 0);
|
||||
|
||||
spin_lock_init(&dev_priv->fb_tracking.lock);
|
||||
}
|
||||
|
||||
@ -4587,6 +4589,11 @@ void i915_gem_load_cleanup(struct drm_device *dev)
|
||||
int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct list_head *phases[] = {
|
||||
&dev_priv->mm.unbound_list,
|
||||
&dev_priv->mm.bound_list,
|
||||
NULL
|
||||
}, **p;
|
||||
|
||||
/* Called just before we write the hibernation image.
|
||||
*
|
||||
@ -4597,16 +4604,18 @@ int i915_gem_freeze_late(struct drm_i915_private *dev_priv)
|
||||
*
|
||||
* To make sure the hibernation image contains the latest state,
|
||||
* we update that state just before writing out the image.
|
||||
*
|
||||
* To try and reduce the hibernation image, we manually shrink
|
||||
* the objects as well.
|
||||
*/
|
||||
|
||||
list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
|
||||
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
|
||||
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
|
||||
}
|
||||
i915_gem_shrink_all(dev_priv);
|
||||
|
||||
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
|
||||
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
|
||||
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
|
||||
for (p = phases; *p; p++) {
|
||||
list_for_each_entry(obj, *p, global_list) {
|
||||
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
|
||||
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -420,22 +420,6 @@ static void i915_gem_context_unpin(struct i915_gem_context *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
void i915_gem_context_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
||||
lockdep_assert_held(&dev->struct_mutex);
|
||||
|
||||
if (i915.enable_execlists) {
|
||||
struct i915_gem_context *ctx;
|
||||
|
||||
list_for_each_entry(ctx, &dev_priv->context_list, link)
|
||||
intel_lr_context_reset(dev_priv, ctx);
|
||||
}
|
||||
|
||||
i915_gem_context_lost(dev_priv);
|
||||
}
|
||||
|
||||
int i915_gem_context_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
@ -170,7 +170,9 @@ search_again:
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_gem_wait_for_idle(dev_priv, true);
|
||||
ret = i915_gem_wait_for_idle(dev_priv,
|
||||
I915_WAIT_INTERRUPTIBLE |
|
||||
I915_WAIT_LOCKED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -275,7 +277,9 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i915_gem_wait_for_idle(dev_priv, true);
|
||||
ret = i915_gem_wait_for_idle(dev_priv,
|
||||
I915_WAIT_INTERRUPTIBLE |
|
||||
I915_WAIT_LOCKED);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1131,13 +1131,25 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req,
|
||||
|
||||
list_for_each_entry(vma, vmas, exec_list) {
|
||||
struct drm_i915_gem_object *obj = vma->obj;
|
||||
struct reservation_object *resv;
|
||||
|
||||
if (obj->flags & other_rings) {
|
||||
ret = i915_gem_object_sync(obj, req);
|
||||
ret = i915_gem_request_await_object
|
||||
(req, obj, obj->base.pending_write_domain);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
resv = i915_gem_object_get_dmabuf_resv(obj);
|
||||
if (resv) {
|
||||
ret = i915_sw_fence_await_reservation
|
||||
(&req->submit, resv, &i915_fence_ops,
|
||||
obj->base.pending_write_domain, 10*HZ,
|
||||
GFP_KERNEL | __GFP_NOWARN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
|
||||
i915_gem_clflush_object(obj, false);
|
||||
}
|
||||
@ -1253,12 +1265,9 @@ static struct i915_gem_context *
|
||||
i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
|
||||
struct intel_engine_cs *engine, const u32 ctx_id)
|
||||
{
|
||||
struct i915_gem_context *ctx = NULL;
|
||||
struct i915_gem_context *ctx;
|
||||
struct i915_ctx_hang_stats *hs;
|
||||
|
||||
if (engine->id != RCS && ctx_id != DEFAULT_CONTEXT_HANDLE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
ctx = i915_gem_context_lookup(file->driver_priv, ctx_id);
|
||||
if (IS_ERR(ctx))
|
||||
return ctx;
|
||||
@ -1538,13 +1547,9 @@ gen8_dispatch_bsd_engine(struct drm_i915_private *dev_priv,
|
||||
struct drm_i915_file_private *file_priv = file->driver_priv;
|
||||
|
||||
/* Check whether the file_priv has already selected one ring. */
|
||||
if ((int)file_priv->bsd_engine < 0) {
|
||||
/* If not, use the ping-pong mechanism to select one. */
|
||||
mutex_lock(&dev_priv->drm.struct_mutex);
|
||||
file_priv->bsd_engine = dev_priv->mm.bsd_engine_dispatch_index;
|
||||
dev_priv->mm.bsd_engine_dispatch_index ^= 1;
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
}
|
||||
if ((int)file_priv->bsd_engine < 0)
|
||||
file_priv->bsd_engine = atomic_fetch_xor(1,
|
||||
&dev_priv->mm.bsd_engine_dispatch_index);
|
||||
|
||||
return file_priv->bsd_engine;
|
||||
}
|
||||
|
@ -32,6 +32,8 @@
|
||||
#include "i915_trace.h"
|
||||
#include "intel_drv.h"
|
||||
|
||||
#define I915_GFP_DMA (GFP_KERNEL | __GFP_HIGHMEM)
|
||||
|
||||
/**
|
||||
* DOC: Global GTT views
|
||||
*
|
||||
@ -122,8 +124,11 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
|
||||
has_full_48bit_ppgtt =
|
||||
IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9;
|
||||
|
||||
if (intel_vgpu_active(dev_priv))
|
||||
has_full_ppgtt = false; /* emulation is too hard */
|
||||
if (intel_vgpu_active(dev_priv)) {
|
||||
/* emulation is too hard */
|
||||
has_full_ppgtt = false;
|
||||
has_full_48bit_ppgtt = false;
|
||||
}
|
||||
|
||||
if (!has_aliasing_ppgtt)
|
||||
return 0;
|
||||
@ -158,7 +163,7 @@ int intel_sanitize_enable_ppgtt(struct drm_i915_private *dev_priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (INTEL_GEN(dev_priv) >= 8 && i915.enable_execlists)
|
||||
if (INTEL_GEN(dev_priv) >= 8 && i915.enable_execlists && has_full_ppgtt)
|
||||
return has_full_48bit_ppgtt ? 3 : 2;
|
||||
else
|
||||
return has_aliasing_ppgtt ? 1 : 0;
|
||||
@ -326,16 +331,16 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr,
|
||||
static int __setup_page_dma(struct drm_device *dev,
|
||||
struct i915_page_dma *p, gfp_t flags)
|
||||
{
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct device *kdev = &dev->pdev->dev;
|
||||
|
||||
p->page = alloc_page(flags);
|
||||
if (!p->page)
|
||||
return -ENOMEM;
|
||||
|
||||
p->daddr = dma_map_page(device,
|
||||
p->daddr = dma_map_page(kdev,
|
||||
p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL);
|
||||
|
||||
if (dma_mapping_error(device, p->daddr)) {
|
||||
if (dma_mapping_error(kdev, p->daddr)) {
|
||||
__free_page(p->page);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -345,15 +350,17 @@ static int __setup_page_dma(struct drm_device *dev,
|
||||
|
||||
static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p)
|
||||
{
|
||||
return __setup_page_dma(dev, p, GFP_KERNEL);
|
||||
return __setup_page_dma(dev, p, I915_GFP_DMA);
|
||||
}
|
||||
|
||||
static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p)
|
||||
{
|
||||
struct pci_dev *pdev = dev->pdev;
|
||||
|
||||
if (WARN_ON(!p->page))
|
||||
return;
|
||||
|
||||
dma_unmap_page(&dev->pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
|
||||
dma_unmap_page(&pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL);
|
||||
__free_page(p->page);
|
||||
memset(p, 0, sizeof(*p));
|
||||
}
|
||||
@ -407,33 +414,18 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p,
|
||||
fill_page_dma(dev, p, v);
|
||||
}
|
||||
|
||||
static struct i915_page_scratch *alloc_scratch_page(struct drm_device *dev)
|
||||
static int
|
||||
setup_scratch_page(struct drm_device *dev,
|
||||
struct i915_page_dma *scratch,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct i915_page_scratch *sp;
|
||||
int ret;
|
||||
|
||||
sp = kzalloc(sizeof(*sp), GFP_KERNEL);
|
||||
if (sp == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
ret = __setup_page_dma(dev, px_base(sp), GFP_DMA32 | __GFP_ZERO);
|
||||
if (ret) {
|
||||
kfree(sp);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
set_pages_uc(px_page(sp), 1);
|
||||
|
||||
return sp;
|
||||
return __setup_page_dma(dev, scratch, gfp | __GFP_ZERO);
|
||||
}
|
||||
|
||||
static void free_scratch_page(struct drm_device *dev,
|
||||
struct i915_page_scratch *sp)
|
||||
static void cleanup_scratch_page(struct drm_device *dev,
|
||||
struct i915_page_dma *scratch)
|
||||
{
|
||||
set_pages_wb(px_page(sp), 1);
|
||||
|
||||
cleanup_px(dev, sp);
|
||||
kfree(sp);
|
||||
cleanup_page_dma(dev, scratch);
|
||||
}
|
||||
|
||||
static struct i915_page_table *alloc_pt(struct drm_device *dev)
|
||||
@ -479,7 +471,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm,
|
||||
{
|
||||
gen8_pte_t scratch_pte;
|
||||
|
||||
scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, true);
|
||||
|
||||
fill_px(vm->dev, pt, scratch_pte);
|
||||
@ -490,9 +482,9 @@ static void gen6_initialize_pt(struct i915_address_space *vm,
|
||||
{
|
||||
gen6_pte_t scratch_pte;
|
||||
|
||||
WARN_ON(px_dma(vm->scratch_page) == 0);
|
||||
WARN_ON(vm->scratch_page.daddr == 0);
|
||||
|
||||
scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, true, 0);
|
||||
|
||||
fill32_px(vm->dev, pt, scratch_pte);
|
||||
@ -776,7 +768,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
|
||||
bool use_scratch)
|
||||
{
|
||||
struct i915_hw_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
|
||||
gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
|
||||
gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, use_scratch);
|
||||
|
||||
if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
|
||||
@ -882,9 +874,9 @@ static int gen8_init_scratch(struct i915_address_space *vm)
|
||||
struct drm_device *dev = vm->dev;
|
||||
int ret;
|
||||
|
||||
vm->scratch_page = alloc_scratch_page(dev);
|
||||
if (IS_ERR(vm->scratch_page))
|
||||
return PTR_ERR(vm->scratch_page);
|
||||
ret = setup_scratch_page(dev, &vm->scratch_page, I915_GFP_DMA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vm->scratch_pt = alloc_pt(dev);
|
||||
if (IS_ERR(vm->scratch_pt)) {
|
||||
@ -918,7 +910,7 @@ free_pd:
|
||||
free_pt:
|
||||
free_pt(dev, vm->scratch_pt);
|
||||
free_scratch_page:
|
||||
free_scratch_page(dev, vm->scratch_page);
|
||||
cleanup_scratch_page(dev, &vm->scratch_page);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -962,7 +954,7 @@ static void gen8_free_scratch(struct i915_address_space *vm)
|
||||
free_pdp(dev, vm->scratch_pdp);
|
||||
free_pd(dev, vm->scratch_pd);
|
||||
free_pt(dev, vm->scratch_pt);
|
||||
free_scratch_page(dev, vm->scratch_page);
|
||||
cleanup_scratch_page(dev, &vm->scratch_page);
|
||||
}
|
||||
|
||||
static void gen8_ppgtt_cleanup_3lvl(struct drm_device *dev,
|
||||
@ -1459,7 +1451,7 @@ static void gen8_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
|
||||
struct i915_address_space *vm = &ppgtt->base;
|
||||
uint64_t start = ppgtt->base.start;
|
||||
uint64_t length = ppgtt->base.total;
|
||||
gen8_pte_t scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
|
||||
gen8_pte_t scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, true);
|
||||
|
||||
if (!USES_FULL_48BIT_PPGTT(vm->dev)) {
|
||||
@ -1576,7 +1568,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
|
||||
uint32_t pte, pde;
|
||||
uint32_t start = ppgtt->base.start, length = ppgtt->base.total;
|
||||
|
||||
scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, true, 0);
|
||||
|
||||
gen6_for_each_pde(unused, &ppgtt->pd, start, length, pde) {
|
||||
@ -1801,7 +1793,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
|
||||
unsigned first_pte = first_entry % GEN6_PTES;
|
||||
unsigned last_pte, i;
|
||||
|
||||
scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, true, 0);
|
||||
|
||||
while (num_entries) {
|
||||
@ -1947,14 +1939,15 @@ unwind_out:
|
||||
static int gen6_init_scratch(struct i915_address_space *vm)
|
||||
{
|
||||
struct drm_device *dev = vm->dev;
|
||||
int ret;
|
||||
|
||||
vm->scratch_page = alloc_scratch_page(dev);
|
||||
if (IS_ERR(vm->scratch_page))
|
||||
return PTR_ERR(vm->scratch_page);
|
||||
ret = setup_scratch_page(dev, &vm->scratch_page, I915_GFP_DMA);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vm->scratch_pt = alloc_pt(dev);
|
||||
if (IS_ERR(vm->scratch_pt)) {
|
||||
free_scratch_page(dev, vm->scratch_page);
|
||||
cleanup_scratch_page(dev, &vm->scratch_page);
|
||||
return PTR_ERR(vm->scratch_pt);
|
||||
}
|
||||
|
||||
@ -1968,7 +1961,7 @@ static void gen6_free_scratch(struct i915_address_space *vm)
|
||||
struct drm_device *dev = vm->dev;
|
||||
|
||||
free_pt(dev, vm->scratch_pt);
|
||||
free_scratch_page(dev, vm->scratch_page);
|
||||
cleanup_scratch_page(dev, &vm->scratch_page);
|
||||
}
|
||||
|
||||
static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
|
||||
@ -2311,12 +2304,7 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
|
||||
|
||||
static void gen8_set_pte(void __iomem *addr, gen8_pte_t pte)
|
||||
{
|
||||
#ifdef writeq
|
||||
writeq(pte, addr);
|
||||
#else
|
||||
iowrite32((u32)pte, addr);
|
||||
iowrite32(pte >> 32, addr + 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gen8_ggtt_insert_page(struct i915_address_space *vm,
|
||||
@ -2509,7 +2497,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
|
||||
first_entry, num_entries, max_entries))
|
||||
num_entries = max_entries;
|
||||
|
||||
scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = gen8_pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC,
|
||||
use_scratch);
|
||||
for (i = 0; i < num_entries; i++)
|
||||
@ -2541,7 +2529,7 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
|
||||
first_entry, num_entries, max_entries))
|
||||
num_entries = max_entries;
|
||||
|
||||
scratch_pte = vm->pte_encode(px_dma(vm->scratch_page),
|
||||
scratch_pte = vm->pte_encode(vm->scratch_page.daddr,
|
||||
I915_CACHE_LLC, use_scratch, 0);
|
||||
|
||||
for (i = 0; i < num_entries; i++)
|
||||
@ -2685,19 +2673,19 @@ static void ggtt_unbind_vma(struct i915_vma *vma)
|
||||
|
||||
void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(obj->base.dev);
|
||||
struct device *kdev = &dev_priv->drm.pdev->dev;
|
||||
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
||||
|
||||
if (unlikely(ggtt->do_idle_maps)) {
|
||||
if (i915_gem_wait_for_idle(dev_priv, false)) {
|
||||
if (i915_gem_wait_for_idle(dev_priv, I915_WAIT_LOCKED)) {
|
||||
DRM_ERROR("Failed to wait for idle; VT'd may hang.\n");
|
||||
/* Wait a bit, in hopes it avoids the hang */
|
||||
udelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
dma_unmap_sg(&dev->pdev->dev, obj->pages->sgl, obj->pages->nents,
|
||||
dma_unmap_sg(kdev, obj->pages->sgl, obj->pages->nents,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
@ -2894,8 +2882,8 @@ static size_t gen9_get_stolen_size(u16 gen9_gmch_ctl)
|
||||
static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
|
||||
{
|
||||
struct pci_dev *pdev = ggtt->base.dev->pdev;
|
||||
struct i915_page_scratch *scratch_page;
|
||||
phys_addr_t phys_addr;
|
||||
int ret;
|
||||
|
||||
/* For Modern GENs the PTEs and register space are split in the BAR */
|
||||
phys_addr = pci_resource_start(pdev, 0) + pci_resource_len(pdev, 0) / 2;
|
||||
@ -2916,16 +2904,16 @@ static int ggtt_probe_common(struct i915_ggtt *ggtt, u64 size)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scratch_page = alloc_scratch_page(ggtt->base.dev);
|
||||
if (IS_ERR(scratch_page)) {
|
||||
ret = setup_scratch_page(ggtt->base.dev,
|
||||
&ggtt->base.scratch_page,
|
||||
GFP_DMA32);
|
||||
if (ret) {
|
||||
DRM_ERROR("Scratch setup failed\n");
|
||||
/* iounmap will also get called at remove, but meh */
|
||||
iounmap(ggtt->gsm);
|
||||
return PTR_ERR(scratch_page);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ggtt->base.scratch_page = scratch_page;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3007,7 +2995,7 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
|
||||
struct i915_ggtt *ggtt = i915_vm_to_ggtt(vm);
|
||||
|
||||
iounmap(ggtt->gsm);
|
||||
free_scratch_page(vm->dev, vm->scratch_page);
|
||||
cleanup_scratch_page(vm->dev, &vm->scratch_page);
|
||||
}
|
||||
|
||||
static int gen8_gmch_probe(struct i915_ggtt *ggtt)
|
||||
@ -3244,8 +3232,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
||||
struct drm_i915_gem_object *obj;
|
||||
struct i915_vma *vma;
|
||||
struct drm_i915_gem_object *obj, *on;
|
||||
|
||||
i915_check_and_clear_faults(dev_priv);
|
||||
|
||||
@ -3253,20 +3240,32 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
|
||||
ggtt->base.clear_range(&ggtt->base, ggtt->base.start, ggtt->base.total,
|
||||
true);
|
||||
|
||||
/* Cache flush objects bound into GGTT and rebind them. */
|
||||
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
|
||||
ggtt->base.closed = true; /* skip rewriting PTE on VMA unbind */
|
||||
|
||||
/* clflush objects bound into the GGTT and rebind them. */
|
||||
list_for_each_entry_safe(obj, on,
|
||||
&dev_priv->mm.bound_list, global_list) {
|
||||
bool ggtt_bound = false;
|
||||
struct i915_vma *vma;
|
||||
|
||||
list_for_each_entry(vma, &obj->vma_list, obj_link) {
|
||||
if (vma->vm != &ggtt->base)
|
||||
continue;
|
||||
|
||||
if (!i915_vma_unbind(vma))
|
||||
continue;
|
||||
|
||||
WARN_ON(i915_vma_bind(vma, obj->cache_level,
|
||||
PIN_UPDATE));
|
||||
ggtt_bound = true;
|
||||
}
|
||||
|
||||
if (obj->pin_display)
|
||||
if (ggtt_bound)
|
||||
WARN_ON(i915_gem_object_set_to_gtt_domain(obj, false));
|
||||
}
|
||||
|
||||
ggtt->base.closed = false;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 8) {
|
||||
if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev))
|
||||
chv_setup_private_ppat(dev_priv);
|
||||
|
@ -312,10 +312,6 @@ struct i915_page_dma {
|
||||
#define px_page(px) (px_base(px)->page)
|
||||
#define px_dma(px) (px_base(px)->daddr)
|
||||
|
||||
struct i915_page_scratch {
|
||||
struct i915_page_dma base;
|
||||
};
|
||||
|
||||
struct i915_page_table {
|
||||
struct i915_page_dma base;
|
||||
|
||||
@ -361,7 +357,7 @@ struct i915_address_space {
|
||||
|
||||
bool closed;
|
||||
|
||||
struct i915_page_scratch *scratch_page;
|
||||
struct i915_page_dma scratch_page;
|
||||
struct i915_page_table *scratch_pt;
|
||||
struct i915_page_directory *scratch_pd;
|
||||
struct i915_page_directory_pointer *scratch_pdp; /* GEN8+ & 48b PPGTT */
|
||||
|
@ -233,16 +233,18 @@ void i915_gem_request_retire_upto(struct drm_i915_gem_request *req)
|
||||
} while (tmp != req);
|
||||
}
|
||||
|
||||
static int i915_gem_check_wedge(unsigned int reset_counter, bool interruptible)
|
||||
static int i915_gem_check_wedge(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
if (__i915_terminally_wedged(reset_counter))
|
||||
struct i915_gpu_error *error = &dev_priv->gpu_error;
|
||||
|
||||
if (i915_terminally_wedged(error))
|
||||
return -EIO;
|
||||
|
||||
if (__i915_reset_in_progress(reset_counter)) {
|
||||
if (i915_reset_in_progress(error)) {
|
||||
/* Non-interruptible callers can't handle -EAGAIN, hence return
|
||||
* -EIO unconditionally for these.
|
||||
*/
|
||||
if (!interruptible)
|
||||
if (!dev_priv->mm.interruptible)
|
||||
return -EIO;
|
||||
|
||||
return -EAGAIN;
|
||||
@ -258,7 +260,9 @@ static int i915_gem_init_seqno(struct drm_i915_private *dev_priv, u32 seqno)
|
||||
|
||||
/* Carefully retire all requests without writing to the rings */
|
||||
for_each_engine(engine, dev_priv) {
|
||||
ret = intel_engine_idle(engine, true);
|
||||
ret = intel_engine_idle(engine,
|
||||
I915_WAIT_INTERRUPTIBLE |
|
||||
I915_WAIT_LOCKED);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -314,6 +318,26 @@ static int i915_gem_get_seqno(struct drm_i915_private *dev_priv, u32 *seqno)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __i915_sw_fence_call
|
||||
submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
|
||||
{
|
||||
struct drm_i915_gem_request *request =
|
||||
container_of(fence, typeof(*request), submit);
|
||||
|
||||
/* Will be called from irq-context when using foreign DMA fences */
|
||||
|
||||
switch (state) {
|
||||
case FENCE_COMPLETE:
|
||||
request->engine->submit_request(request);
|
||||
break;
|
||||
|
||||
case FENCE_FREE:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_request_alloc - allocate a request structure
|
||||
*
|
||||
@ -331,7 +355,6 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
struct i915_gem_context *ctx)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
unsigned int reset_counter = i915_reset_counter(&dev_priv->gpu_error);
|
||||
struct drm_i915_gem_request *req;
|
||||
u32 seqno;
|
||||
int ret;
|
||||
@ -340,7 +363,7 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
* EIO if the GPU is already wedged, or EAGAIN to drop the struct_mutex
|
||||
* and restart.
|
||||
*/
|
||||
ret = i915_gem_check_wedge(reset_counter, dev_priv->mm.interruptible);
|
||||
ret = i915_gem_check_wedge(dev_priv);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@ -393,6 +416,8 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
engine->fence_context,
|
||||
seqno);
|
||||
|
||||
i915_sw_fence_init(&req->submit, submit_notify);
|
||||
|
||||
INIT_LIST_HEAD(&req->active_list);
|
||||
req->i915 = dev_priv;
|
||||
req->engine = engine;
|
||||
@ -402,7 +427,6 @@ i915_gem_request_alloc(struct intel_engine_cs *engine,
|
||||
req->previous_context = NULL;
|
||||
req->file_priv = NULL;
|
||||
req->batch = NULL;
|
||||
req->elsp_submitted = 0;
|
||||
|
||||
/*
|
||||
* Reserve space in the ring buffer for all the commands required to
|
||||
@ -436,6 +460,94 @@ err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gem_request_await_request(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_request *from)
|
||||
{
|
||||
int idx, ret;
|
||||
|
||||
GEM_BUG_ON(to == from);
|
||||
|
||||
if (to->engine == from->engine)
|
||||
return 0;
|
||||
|
||||
idx = intel_engine_sync_index(from->engine, to->engine);
|
||||
if (from->fence.seqno <= from->engine->semaphore.sync_seqno[idx])
|
||||
return 0;
|
||||
|
||||
trace_i915_gem_ring_sync_to(to, from);
|
||||
if (!i915.semaphores) {
|
||||
if (!i915_spin_request(from, TASK_INTERRUPTIBLE, 2)) {
|
||||
ret = i915_sw_fence_await_dma_fence(&to->submit,
|
||||
&from->fence, 0,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = to->engine->semaphore.sync_to(to, from);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
from->engine->semaphore.sync_seqno[idx] = from->fence.seqno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_request_await_object - set this request to (async) wait upon a bo
|
||||
*
|
||||
* @to: request we are wishing to use
|
||||
* @obj: object which may be in use on another ring.
|
||||
*
|
||||
* This code is meant to abstract object synchronization with the GPU.
|
||||
* Conceptually we serialise writes between engines inside the GPU.
|
||||
* We only allow one engine to write into a buffer at any time, but
|
||||
* multiple readers. To ensure each has a coherent view of memory, we must:
|
||||
*
|
||||
* - If there is an outstanding write request to the object, the new
|
||||
* request must wait for it to complete (either CPU or in hw, requests
|
||||
* on the same ring will be naturally ordered).
|
||||
*
|
||||
* - If we are a write request (pending_write_domain is set), the new
|
||||
* request must wait for outstanding read requests to complete.
|
||||
*
|
||||
* Returns 0 if successful, else propagates up the lower layer error.
|
||||
*/
|
||||
int
|
||||
i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_object *obj,
|
||||
bool write)
|
||||
{
|
||||
struct i915_gem_active *active;
|
||||
unsigned long active_mask;
|
||||
int idx;
|
||||
|
||||
if (write) {
|
||||
active_mask = i915_gem_object_get_active(obj);
|
||||
active = obj->last_read;
|
||||
} else {
|
||||
active_mask = 1;
|
||||
active = &obj->last_write;
|
||||
}
|
||||
|
||||
for_each_active(active_mask, idx) {
|
||||
struct drm_i915_gem_request *request;
|
||||
int ret;
|
||||
|
||||
request = i915_gem_active_peek(&active[idx],
|
||||
&obj->base.dev->struct_mutex);
|
||||
if (!request)
|
||||
continue;
|
||||
|
||||
ret = i915_gem_request_await_request(to, request);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_gem_mark_busy(const struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
@ -466,10 +578,13 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct intel_ring *ring = request->ring;
|
||||
struct drm_i915_gem_request *prev;
|
||||
u32 request_start;
|
||||
u32 reserved_tail;
|
||||
int ret;
|
||||
|
||||
trace_i915_gem_request_add(request);
|
||||
|
||||
/*
|
||||
* To ensure that this call will not fail, space for its emissions
|
||||
* should already have been reserved in the ring buffer. Let the ring
|
||||
@ -493,20 +608,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
||||
WARN(ret, "engine->emit_flush() failed: %d!\n", ret);
|
||||
}
|
||||
|
||||
trace_i915_gem_request_add(request);
|
||||
|
||||
/* Seal the request and mark it as pending execution. Note that
|
||||
* we may inspect this state, without holding any locks, during
|
||||
* hangcheck. Hence we apply the barrier to ensure that we do not
|
||||
* see a more recent value in the hws than we are tracking.
|
||||
*/
|
||||
request->emitted_jiffies = jiffies;
|
||||
request->previous_seqno = engine->last_submitted_seqno;
|
||||
engine->last_submitted_seqno = request->fence.seqno;
|
||||
i915_gem_active_set(&engine->last_request, request);
|
||||
list_add_tail(&request->link, &engine->request_list);
|
||||
list_add_tail(&request->ring_link, &ring->request_list);
|
||||
|
||||
/* Record the position of the start of the breadcrumb so that
|
||||
* should we detect the updated seqno part-way through the
|
||||
* GPU processing the request, we never over-estimate the
|
||||
@ -527,8 +628,40 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
|
||||
"for adding the request (%d bytes)\n",
|
||||
reserved_tail, ret);
|
||||
|
||||
/* Seal the request and mark it as pending execution. Note that
|
||||
* we may inspect this state, without holding any locks, during
|
||||
* hangcheck. Hence we apply the barrier to ensure that we do not
|
||||
* see a more recent value in the hws than we are tracking.
|
||||
*/
|
||||
|
||||
prev = i915_gem_active_raw(&engine->last_request,
|
||||
&request->i915->drm.struct_mutex);
|
||||
if (prev)
|
||||
i915_sw_fence_await_sw_fence(&request->submit, &prev->submit,
|
||||
&request->submitq);
|
||||
|
||||
request->emitted_jiffies = jiffies;
|
||||
request->previous_seqno = engine->last_submitted_seqno;
|
||||
engine->last_submitted_seqno = request->fence.seqno;
|
||||
i915_gem_active_set(&engine->last_request, request);
|
||||
list_add_tail(&request->link, &engine->request_list);
|
||||
list_add_tail(&request->ring_link, &ring->request_list);
|
||||
|
||||
i915_gem_mark_busy(engine);
|
||||
engine->submit_request(request);
|
||||
|
||||
local_bh_disable();
|
||||
i915_sw_fence_commit(&request->submit);
|
||||
local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
|
||||
}
|
||||
|
||||
static void reset_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&q->lock, flags);
|
||||
if (list_empty(&wait->task_list))
|
||||
__add_wait_queue(q, wait);
|
||||
spin_unlock_irqrestore(&q->lock, flags);
|
||||
}
|
||||
|
||||
static unsigned long local_clock_us(unsigned int *cpu)
|
||||
@ -598,7 +731,7 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
||||
/**
|
||||
* i915_wait_request - wait until execution of request has finished
|
||||
* @req: duh!
|
||||
* @interruptible: do an interruptible wait (normally yes)
|
||||
* @flags: how to wait
|
||||
* @timeout: in - how long to wait (NULL forever); out - how much time remaining
|
||||
* @rps: client to charge for RPS boosting
|
||||
*
|
||||
@ -613,17 +746,22 @@ bool __i915_spin_request(const struct drm_i915_gem_request *req,
|
||||
* errno with remaining time filled in timeout argument.
|
||||
*/
|
||||
int i915_wait_request(struct drm_i915_gem_request *req,
|
||||
bool interruptible,
|
||||
unsigned int flags,
|
||||
s64 *timeout,
|
||||
struct intel_rps_client *rps)
|
||||
{
|
||||
int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
|
||||
const int state = flags & I915_WAIT_INTERRUPTIBLE ?
|
||||
TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
|
||||
DEFINE_WAIT(reset);
|
||||
struct intel_wait wait;
|
||||
unsigned long timeout_remain;
|
||||
int ret = 0;
|
||||
|
||||
might_sleep();
|
||||
#if IS_ENABLED(CONFIG_LOCKDEP)
|
||||
GEM_BUG_ON(!!lockdep_is_held(&req->i915->drm.struct_mutex) !=
|
||||
!!(flags & I915_WAIT_LOCKED));
|
||||
#endif
|
||||
|
||||
if (i915_gem_request_completed(req))
|
||||
return 0;
|
||||
@ -666,7 +804,8 @@ int i915_wait_request(struct drm_i915_gem_request *req,
|
||||
goto complete;
|
||||
|
||||
set_current_state(state);
|
||||
add_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
|
||||
if (flags & I915_WAIT_LOCKED)
|
||||
add_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
|
||||
|
||||
intel_wait_init(&wait, req->fence.seqno);
|
||||
if (intel_engine_add_wait(req->engine, &wait))
|
||||
@ -702,14 +841,35 @@ wakeup:
|
||||
if (__i915_request_irq_complete(req))
|
||||
break;
|
||||
|
||||
/* If the GPU is hung, and we hold the lock, reset the GPU
|
||||
* and then check for completion. On a full reset, the engine's
|
||||
* HW seqno will be advanced passed us and we are complete.
|
||||
* If we do a partial reset, we have to wait for the GPU to
|
||||
* resume and update the breadcrumb.
|
||||
*
|
||||
* If we don't hold the mutex, we can just wait for the worker
|
||||
* to come along and update the breadcrumb (either directly
|
||||
* itself, or indirectly by recovering the GPU).
|
||||
*/
|
||||
if (flags & I915_WAIT_LOCKED &&
|
||||
i915_reset_in_progress(&req->i915->gpu_error)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
i915_reset(req->i915);
|
||||
reset_wait_queue(&req->i915->gpu_error.wait_queue,
|
||||
&reset);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only spin if we know the GPU is processing this request */
|
||||
if (i915_spin_request(req, state, 2))
|
||||
break;
|
||||
}
|
||||
remove_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
|
||||
|
||||
intel_engine_remove_wait(req->engine, &wait);
|
||||
if (flags & I915_WAIT_LOCKED)
|
||||
remove_wait_queue(&req->i915->gpu_error.wait_queue, &reset);
|
||||
__set_current_state(TASK_RUNNING);
|
||||
|
||||
complete:
|
||||
trace_i915_gem_request_wait_end(req);
|
||||
|
||||
@ -749,21 +909,24 @@ complete:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void engine_retire_requests(struct intel_engine_cs *engine)
|
||||
static bool engine_retire_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *request, *next;
|
||||
|
||||
list_for_each_entry_safe(request, next, &engine->request_list, link) {
|
||||
if (!i915_gem_request_completed(request))
|
||||
break;
|
||||
return false;
|
||||
|
||||
i915_gem_request_retire(request);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
unsigned int tmp;
|
||||
|
||||
lockdep_assert_held(&dev_priv->drm.struct_mutex);
|
||||
|
||||
@ -772,11 +935,9 @@ void i915_gem_retire_requests(struct drm_i915_private *dev_priv)
|
||||
|
||||
GEM_BUG_ON(!dev_priv->gt.awake);
|
||||
|
||||
for_each_engine(engine, dev_priv) {
|
||||
engine_retire_requests(engine);
|
||||
if (!intel_engine_is_active(engine))
|
||||
for_each_engine_masked(engine, dev_priv, dev_priv->gt.active_engines, tmp)
|
||||
if (engine_retire_requests(engine))
|
||||
dev_priv->gt.active_engines &= ~intel_engine_flag(engine);
|
||||
}
|
||||
|
||||
if (dev_priv->gt.active_engines == 0)
|
||||
queue_delayed_work(dev_priv->wq,
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/fence.h>
|
||||
|
||||
#include "i915_gem.h"
|
||||
#include "i915_sw_fence.h"
|
||||
|
||||
struct intel_wait {
|
||||
struct rb_node node;
|
||||
@ -82,26 +83,32 @@ struct drm_i915_gem_request {
|
||||
struct intel_ring *ring;
|
||||
struct intel_signal_node signaling;
|
||||
|
||||
struct i915_sw_fence submit;
|
||||
wait_queue_t submitq;
|
||||
|
||||
/** GEM sequence number associated with the previous request,
|
||||
* when the HWS breadcrumb is equal to this the GPU is processing
|
||||
* this request.
|
||||
*/
|
||||
u32 previous_seqno;
|
||||
|
||||
/** Position in the ringbuffer of the start of the request */
|
||||
/** Position in the ring of the start of the request */
|
||||
u32 head;
|
||||
|
||||
/**
|
||||
* Position in the ringbuffer of the start of the postfix.
|
||||
* This is required to calculate the maximum available ringbuffer
|
||||
* space without overwriting the postfix.
|
||||
* Position in the ring of the start of the postfix.
|
||||
* This is required to calculate the maximum available ring space
|
||||
* without overwriting the postfix.
|
||||
*/
|
||||
u32 postfix;
|
||||
|
||||
/** Position in the ringbuffer of the end of the whole request */
|
||||
/** Position in the ring of the end of the whole request */
|
||||
u32 tail;
|
||||
|
||||
/** Preallocate space in the ringbuffer for the emitting the request */
|
||||
/** Position in the ring of the end of any workarounds after the tail */
|
||||
u32 wa_tail;
|
||||
|
||||
/** Preallocate space in the ring for the emitting the request */
|
||||
u32 reserved_space;
|
||||
|
||||
/**
|
||||
@ -134,27 +141,8 @@ struct drm_i915_gem_request {
|
||||
/** file_priv list entry for this request */
|
||||
struct list_head client_list;
|
||||
|
||||
/**
|
||||
* The ELSP only accepts two elements at a time, so we queue
|
||||
* context/tail pairs on a given queue (ring->execlist_queue) until the
|
||||
* hardware is available. The queue serves a double purpose: we also use
|
||||
* it to keep track of the up to 2 contexts currently in the hardware
|
||||
* (usually one in execution and the other queued up by the GPU): We
|
||||
* only remove elements from the head of the queue when the hardware
|
||||
* informs us that an element has been completed.
|
||||
*
|
||||
* All accesses to the queue are mediated by a spinlock
|
||||
* (ring->execlist_lock).
|
||||
*/
|
||||
|
||||
/** Execlist link in the submission queue.*/
|
||||
/** Link in the execlist submission queue, guarded by execlist_lock. */
|
||||
struct list_head execlist_link;
|
||||
|
||||
/** Execlists no. of times this request has been sent to the ELSP */
|
||||
int elsp_submitted;
|
||||
|
||||
/** Execlists context hardware id. */
|
||||
unsigned int ctx_hw_id;
|
||||
};
|
||||
|
||||
extern const struct fence_ops i915_fence_ops;
|
||||
@ -222,6 +210,11 @@ static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
|
||||
*pdst = src;
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_request_await_object(struct drm_i915_gem_request *to,
|
||||
struct drm_i915_gem_object *obj,
|
||||
bool write);
|
||||
|
||||
void __i915_add_request(struct drm_i915_gem_request *req, bool flush_caches);
|
||||
#define i915_add_request(req) \
|
||||
__i915_add_request(req, true)
|
||||
@ -234,10 +227,12 @@ struct intel_rps_client;
|
||||
#define IS_RPS_USER(p) (!IS_ERR_OR_NULL(p))
|
||||
|
||||
int i915_wait_request(struct drm_i915_gem_request *req,
|
||||
bool interruptible,
|
||||
unsigned int flags,
|
||||
s64 *timeout,
|
||||
struct intel_rps_client *rps)
|
||||
__attribute__((nonnull(1)));
|
||||
#define I915_WAIT_INTERRUPTIBLE BIT(0)
|
||||
#define I915_WAIT_LOCKED BIT(1) /* struct_mutex held, handle GPU reset */
|
||||
|
||||
static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine);
|
||||
|
||||
@ -472,6 +467,19 @@ __i915_gem_active_get_rcu(const struct i915_gem_active *active)
|
||||
if (!request || i915_gem_request_completed(request))
|
||||
return NULL;
|
||||
|
||||
/* An especially silly compiler could decide to recompute the
|
||||
* result of i915_gem_request_completed, more specifically
|
||||
* re-emit the load for request->fence.seqno. A race would catch
|
||||
* a later seqno value, which could flip the result from true to
|
||||
* false. Which means part of the instructions below might not
|
||||
* be executed, while later on instructions are executed. Due to
|
||||
* barriers within the refcounting the inconsistency can't reach
|
||||
* past the call to i915_gem_request_get_rcu, but not executing
|
||||
* that while still executing i915_gem_request_put() creates
|
||||
* havoc enough. Prevent this with a compiler barrier.
|
||||
*/
|
||||
barrier();
|
||||
|
||||
request = i915_gem_request_get_rcu(request);
|
||||
|
||||
/* What stops the following rcu_access_pointer() from occurring
|
||||
@ -578,13 +586,15 @@ i915_gem_active_wait(const struct i915_gem_active *active, struct mutex *mutex)
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
return i915_wait_request(request, true, NULL, NULL);
|
||||
return i915_wait_request(request,
|
||||
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_active_wait_unlocked - waits until the request is completed
|
||||
* @active - the active request on which to wait
|
||||
* @interruptible - whether the wait can be woken by a userspace signal
|
||||
* @flags - how to wait
|
||||
* @timeout - how long to wait at most
|
||||
* @rps - userspace client to charge for a waitboost
|
||||
*
|
||||
@ -605,7 +615,7 @@ i915_gem_active_wait(const struct i915_gem_active *active, struct mutex *mutex)
|
||||
*/
|
||||
static inline int
|
||||
i915_gem_active_wait_unlocked(const struct i915_gem_active *active,
|
||||
bool interruptible,
|
||||
unsigned int flags,
|
||||
s64 *timeout,
|
||||
struct intel_rps_client *rps)
|
||||
{
|
||||
@ -614,7 +624,7 @@ i915_gem_active_wait_unlocked(const struct i915_gem_active *active,
|
||||
|
||||
request = i915_gem_active_get_unlocked(active);
|
||||
if (request) {
|
||||
ret = i915_wait_request(request, interruptible, timeout, rps);
|
||||
ret = i915_wait_request(request, flags, timeout, rps);
|
||||
i915_gem_request_put(request);
|
||||
}
|
||||
|
||||
@ -641,7 +651,9 @@ i915_gem_active_retire(struct i915_gem_active *active,
|
||||
if (!request)
|
||||
return 0;
|
||||
|
||||
ret = i915_wait_request(request, true, NULL, NULL);
|
||||
ret = i915_wait_request(request,
|
||||
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
|
||||
NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -323,7 +323,7 @@ i915_gem_shrinker_lock_uninterruptible(struct drm_i915_private *dev_priv,
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies_timeout(timeout_ms);
|
||||
|
||||
do {
|
||||
if (i915_gem_wait_for_idle(dev_priv, false) == 0 &&
|
||||
if (i915_gem_wait_for_idle(dev_priv, 0) == 0 &&
|
||||
i915_gem_shrinker_lock(&dev_priv->drm, &slu->unlock))
|
||||
break;
|
||||
|
||||
@ -414,7 +414,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr
|
||||
return NOTIFY_DONE;
|
||||
|
||||
/* Force everything onto the inactive lists */
|
||||
ret = i915_gem_wait_for_idle(dev_priv, false);
|
||||
ret = i915_gem_wait_for_idle(dev_priv, I915_WAIT_LOCKED);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
@ -92,6 +92,7 @@ void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv,
|
||||
static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
||||
struct resource *r;
|
||||
u32 base;
|
||||
@ -111,7 +112,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
if (INTEL_INFO(dev)->gen >= 3) {
|
||||
u32 bsm;
|
||||
|
||||
pci_read_config_dword(dev->pdev, INTEL_BSM, &bsm);
|
||||
pci_read_config_dword(pdev, INTEL_BSM, &bsm);
|
||||
|
||||
base = bsm & INTEL_BSM_MASK;
|
||||
} else if (IS_I865G(dev)) {
|
||||
@ -119,7 +120,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
u16 toud = 0;
|
||||
u8 tmp;
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I845_ESMRAMC, &tmp);
|
||||
|
||||
if (tmp & TSEG_ENABLE) {
|
||||
@ -133,7 +134,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I865_TOUD, &toud);
|
||||
|
||||
base = (toud << 16) + tseg_size;
|
||||
@ -142,13 +143,13 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
u32 tom;
|
||||
u8 tmp;
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I85X_ESMRAMC, &tmp);
|
||||
|
||||
if (tmp & TSEG_ENABLE)
|
||||
tseg_size = MB(1);
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 1),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 1),
|
||||
I85X_DRB3, &tmp);
|
||||
tom = tmp * MB(32);
|
||||
|
||||
@ -158,7 +159,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
u32 tom;
|
||||
u8 tmp;
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I845_ESMRAMC, &tmp);
|
||||
|
||||
if (tmp & TSEG_ENABLE) {
|
||||
@ -172,7 +173,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I830_DRB3, &tmp);
|
||||
tom = tmp * MB(32);
|
||||
|
||||
@ -182,7 +183,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
u32 tom;
|
||||
u8 tmp;
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I830_ESMRAMC, &tmp);
|
||||
|
||||
if (tmp & TSEG_ENABLE) {
|
||||
@ -192,7 +193,7 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
|
||||
tseg_size = KB(512);
|
||||
}
|
||||
|
||||
pci_bus_read_config_byte(dev->pdev->bus, PCI_DEVFN(0, 0),
|
||||
pci_bus_read_config_byte(pdev->bus, PCI_DEVFN(0, 0),
|
||||
I830_DRB3, &tmp);
|
||||
tom = tmp * MB(32);
|
||||
|
||||
|
@ -68,7 +68,7 @@ static void wait_rendering(struct drm_i915_gem_object *obj)
|
||||
|
||||
for_each_active(active, idx)
|
||||
i915_gem_active_wait_unlocked(&obj->last_read[idx],
|
||||
false, NULL, NULL);
|
||||
0, NULL, NULL);
|
||||
}
|
||||
|
||||
static void cancel_userptr(struct work_struct *work)
|
||||
|
@ -336,6 +336,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
|
||||
{
|
||||
struct drm_device *dev = error_priv->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct drm_i915_error_state *error = error_priv->error;
|
||||
struct drm_i915_error_object *obj;
|
||||
int i, j, offset, elt;
|
||||
@ -367,11 +368,11 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
|
||||
}
|
||||
err_printf(m, "Reset count: %u\n", error->reset_count);
|
||||
err_printf(m, "Suspend count: %u\n", error->suspend_count);
|
||||
err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
|
||||
err_printf(m, "PCI Revision: 0x%02x\n", dev->pdev->revision);
|
||||
err_printf(m, "PCI ID: 0x%04x\n", pdev->device);
|
||||
err_printf(m, "PCI Revision: 0x%02x\n", pdev->revision);
|
||||
err_printf(m, "PCI Subsystem: %04x:%04x\n",
|
||||
dev->pdev->subsystem_vendor,
|
||||
dev->pdev->subsystem_device);
|
||||
pdev->subsystem_vendor,
|
||||
pdev->subsystem_device);
|
||||
err_printf(m, "IOMMU enabled?: %d\n", error->iommu);
|
||||
|
||||
if (HAS_CSR(dev)) {
|
||||
@ -488,7 +489,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
|
||||
}
|
||||
}
|
||||
|
||||
if (ee->num_waiters) {
|
||||
if (IS_ERR(ee->waiters)) {
|
||||
err_printf(m, "%s --- ? waiters [unable to acquire spinlock]\n",
|
||||
dev_priv->engine[i].name);
|
||||
} else if (ee->num_waiters) {
|
||||
err_printf(m, "%s --- %d waiters\n",
|
||||
dev_priv->engine[i].name,
|
||||
ee->num_waiters);
|
||||
@ -647,7 +651,8 @@ static void i915_error_state_free(struct kref *error_ref)
|
||||
i915_error_object_free(ee->wa_ctx);
|
||||
|
||||
kfree(ee->requests);
|
||||
kfree(ee->waiters);
|
||||
if (!IS_ERR_OR_NULL(ee->waiters))
|
||||
kfree(ee->waiters);
|
||||
}
|
||||
|
||||
i915_error_object_free(error->semaphore);
|
||||
@ -932,7 +937,14 @@ static void error_record_engine_waiters(struct intel_engine_cs *engine,
|
||||
ee->num_waiters = 0;
|
||||
ee->waiters = NULL;
|
||||
|
||||
spin_lock(&b->lock);
|
||||
if (RB_EMPTY_ROOT(&b->waiters))
|
||||
return;
|
||||
|
||||
if (!spin_trylock(&b->lock)) {
|
||||
ee->waiters = ERR_PTR(-EDEADLK);
|
||||
return;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
for (rb = rb_first(&b->waiters); rb != NULL; rb = rb_next(rb))
|
||||
count++;
|
||||
@ -946,9 +958,13 @@ static void error_record_engine_waiters(struct intel_engine_cs *engine,
|
||||
if (!waiter)
|
||||
return;
|
||||
|
||||
ee->waiters = waiter;
|
||||
if (!spin_trylock(&b->lock)) {
|
||||
kfree(waiter);
|
||||
ee->waiters = ERR_PTR(-EDEADLK);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock(&b->lock);
|
||||
ee->waiters = waiter;
|
||||
for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
|
||||
struct intel_wait *w = container_of(rb, typeof(*w), node);
|
||||
|
||||
@ -1009,7 +1025,7 @@ static void error_record_engine_registers(struct drm_i915_error_state *error,
|
||||
if (INTEL_GEN(dev_priv) > 2)
|
||||
ee->mode = I915_READ_MODE(engine);
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev_priv)) {
|
||||
if (!HWS_NEEDS_PHYSICAL(dev_priv)) {
|
||||
i915_reg_t mmio;
|
||||
|
||||
if (IS_GEN7(dev_priv)) {
|
||||
|
@ -103,9 +103,6 @@
|
||||
#define HOST2GUC_INTERRUPT _MMIO(0xc4c8)
|
||||
#define HOST2GUC_TRIGGER (1<<0)
|
||||
|
||||
#define DRBMISC1 0x1984
|
||||
#define DOORBELL_ENABLE (1<<0)
|
||||
|
||||
#define GEN8_DRBREGL(x) _MMIO(0x1000 + (x) * 8)
|
||||
#define GEN8_DRB_VALID (1<<0)
|
||||
#define GEN8_DRBREGU(x) _MMIO(0x1000 + (x) * 8 + 4)
|
||||
|
@ -59,7 +59,7 @@
|
||||
* WQ_TYPE_INORDER is needed to support legacy submission via GuC, which
|
||||
* represents in-order queue. The kernel driver packs ring tail pointer and an
|
||||
* ELSP context descriptor dword into Work Item.
|
||||
* See guc_add_workqueue_item()
|
||||
* See guc_wq_item_append()
|
||||
*
|
||||
*/
|
||||
|
||||
@ -114,10 +114,8 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
|
||||
if (ret != -ETIMEDOUT)
|
||||
ret = -EIO;
|
||||
|
||||
DRM_ERROR("GUC: host2guc action 0x%X failed. ret=%d "
|
||||
"status=0x%08X response=0x%08X\n",
|
||||
data[0], ret, status,
|
||||
I915_READ(SOFT_SCRATCH(15)));
|
||||
DRM_WARN("Action 0x%X failed; ret=%d status=0x%08X response=0x%08X\n",
|
||||
data[0], ret, status, I915_READ(SOFT_SCRATCH(15)));
|
||||
|
||||
dev_priv->guc.action_fail += 1;
|
||||
dev_priv->guc.action_err = ret;
|
||||
@ -290,7 +288,7 @@ static uint32_t select_doorbell_cacheline(struct intel_guc *guc)
|
||||
/*
|
||||
* Initialise the process descriptor shared with the GuC firmware.
|
||||
*/
|
||||
static void guc_init_proc_desc(struct intel_guc *guc,
|
||||
static void guc_proc_desc_init(struct intel_guc *guc,
|
||||
struct i915_guc_client *client)
|
||||
{
|
||||
struct guc_process_desc *desc;
|
||||
@ -322,7 +320,7 @@ static void guc_init_proc_desc(struct intel_guc *guc,
|
||||
* write queue, etc).
|
||||
*/
|
||||
|
||||
static void guc_init_ctx_desc(struct intel_guc *guc,
|
||||
static void guc_ctx_desc_init(struct intel_guc *guc,
|
||||
struct i915_guc_client *client)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = guc_to_i915(guc);
|
||||
@ -330,6 +328,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
|
||||
struct i915_gem_context *ctx = client->owner;
|
||||
struct guc_context_desc desc;
|
||||
struct sg_table *sg;
|
||||
unsigned int tmp;
|
||||
u32 gfx_addr;
|
||||
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
@ -339,7 +338,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
|
||||
desc.priority = client->priority;
|
||||
desc.db_id = client->doorbell_id;
|
||||
|
||||
for_each_engine_masked(engine, dev_priv, client->engines) {
|
||||
for_each_engine_masked(engine, dev_priv, client->engines, tmp) {
|
||||
struct intel_context *ce = &ctx->engine[engine->id];
|
||||
uint32_t guc_engine_id = engine->guc_id;
|
||||
struct guc_execlist_context *lrc = &desc.lrc[guc_engine_id];
|
||||
@ -400,7 +399,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
|
||||
sizeof(desc) * client->ctx_index);
|
||||
}
|
||||
|
||||
static void guc_fini_ctx_desc(struct intel_guc *guc,
|
||||
static void guc_ctx_desc_fini(struct intel_guc *guc,
|
||||
struct i915_guc_client *client)
|
||||
{
|
||||
struct guc_context_desc desc;
|
||||
@ -414,7 +413,7 @@ static void guc_fini_ctx_desc(struct intel_guc *guc,
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_guc_wq_check_space() - check that the GuC can accept a request
|
||||
* i915_guc_wq_reserve() - reserve space in the GuC's workqueue
|
||||
* @request: request associated with the commands
|
||||
*
|
||||
* Return: 0 if space is available
|
||||
@ -422,35 +421,39 @@ static void guc_fini_ctx_desc(struct intel_guc *guc,
|
||||
*
|
||||
* This function must be called (and must return 0) before a request
|
||||
* is submitted to the GuC via i915_guc_submit() below. Once a result
|
||||
* of 0 has been returned, it remains valid until (but only until)
|
||||
* the next call to submit().
|
||||
* of 0 has been returned, it must be balanced by a corresponding
|
||||
* call to submit().
|
||||
*
|
||||
* This precheck allows the caller to determine in advance that space
|
||||
* Reservation allows the caller to determine in advance that space
|
||||
* will be available for the next submission before committing resources
|
||||
* to it, and helps avoid late failures with complicated recovery paths.
|
||||
*/
|
||||
int i915_guc_wq_check_space(struct drm_i915_gem_request *request)
|
||||
int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
|
||||
{
|
||||
const size_t wqi_size = sizeof(struct guc_wq_item);
|
||||
struct i915_guc_client *gc = request->i915->guc.execbuf_client;
|
||||
struct guc_process_desc *desc;
|
||||
struct guc_process_desc *desc = gc->client_base + gc->proc_desc_offset;
|
||||
u32 freespace;
|
||||
int ret;
|
||||
|
||||
GEM_BUG_ON(gc == NULL);
|
||||
|
||||
desc = gc->client_base + gc->proc_desc_offset;
|
||||
|
||||
spin_lock(&gc->wq_lock);
|
||||
freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
|
||||
if (likely(freespace >= wqi_size))
|
||||
return 0;
|
||||
freespace -= gc->wq_rsvd;
|
||||
if (likely(freespace >= wqi_size)) {
|
||||
gc->wq_rsvd += wqi_size;
|
||||
ret = 0;
|
||||
} else {
|
||||
gc->no_wq_space++;
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
spin_unlock(&gc->wq_lock);
|
||||
|
||||
gc->no_wq_space += 1;
|
||||
|
||||
return -EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void guc_add_workqueue_item(struct i915_guc_client *gc,
|
||||
struct drm_i915_gem_request *rq)
|
||||
/* Construct a Work Item and append it to the GuC's Work Queue */
|
||||
static void guc_wq_item_append(struct i915_guc_client *gc,
|
||||
struct drm_i915_gem_request *rq)
|
||||
{
|
||||
/* wqi_len is in DWords, and does not include the one-word header */
|
||||
const size_t wqi_size = sizeof(struct guc_wq_item);
|
||||
@ -463,7 +466,7 @@ static void guc_add_workqueue_item(struct i915_guc_client *gc,
|
||||
|
||||
desc = gc->client_base + gc->proc_desc_offset;
|
||||
|
||||
/* Free space is guaranteed, see i915_guc_wq_check_space() above */
|
||||
/* Free space is guaranteed, see i915_guc_wq_reserve() above */
|
||||
freespace = CIRC_SPACE(gc->wq_tail, desc->head, gc->wq_size);
|
||||
GEM_BUG_ON(freespace < wqi_size);
|
||||
|
||||
@ -481,12 +484,14 @@ static void guc_add_workqueue_item(struct i915_guc_client *gc,
|
||||
* workqueue buffer dw by dw.
|
||||
*/
|
||||
BUILD_BUG_ON(wqi_size != 16);
|
||||
GEM_BUG_ON(gc->wq_rsvd < wqi_size);
|
||||
|
||||
/* postincrement WQ tail for next time */
|
||||
wq_off = gc->wq_tail;
|
||||
GEM_BUG_ON(wq_off & (wqi_size - 1));
|
||||
gc->wq_tail += wqi_size;
|
||||
gc->wq_tail &= gc->wq_size - 1;
|
||||
GEM_BUG_ON(wq_off & (wqi_size - 1));
|
||||
gc->wq_rsvd -= wqi_size;
|
||||
|
||||
/* WQ starts from the page after doorbell / process_desc */
|
||||
wq_page = (wq_off + GUC_DB_SIZE) >> PAGE_SHIFT;
|
||||
@ -551,8 +556,8 @@ static int guc_ring_doorbell(struct i915_guc_client *gc)
|
||||
if (db_ret.db_status == GUC_DOORBELL_DISABLED)
|
||||
break;
|
||||
|
||||
DRM_ERROR("Cookie mismatch. Expected %d, returned %d\n",
|
||||
db_cmp.cookie, db_ret.cookie);
|
||||
DRM_WARN("Cookie mismatch. Expected %d, found %d\n",
|
||||
db_cmp.cookie, db_ret.cookie);
|
||||
|
||||
/* update the cookie to newly read cookie from GuC */
|
||||
db_cmp.cookie = db_ret.cookie;
|
||||
@ -571,14 +576,13 @@ static int guc_ring_doorbell(struct i915_guc_client *gc)
|
||||
* Return: 0 on success, otherwise an errno.
|
||||
* (Note: nonzero really shouldn't happen!)
|
||||
*
|
||||
* The caller must have already called i915_guc_wq_check_space() above
|
||||
* with a result of 0 (success) since the last request submission. This
|
||||
* guarantees that there is space in the work queue for the new request,
|
||||
* so enqueuing the item cannot fail.
|
||||
* The caller must have already called i915_guc_wq_reserve() above with
|
||||
* a result of 0 (success), guaranteeing that there is space in the work
|
||||
* queue for the new request, so enqueuing the item cannot fail.
|
||||
*
|
||||
* Bad Things Will Happen if the caller violates this protocol e.g. calls
|
||||
* submit() when check() says there's no space, or calls submit() multiple
|
||||
* times with no intervening check().
|
||||
* submit() when _reserve() says there's no space, or calls _submit()
|
||||
* a different number of times from (successful) calls to _reserve().
|
||||
*
|
||||
* The only error here arises if the doorbell hardware isn't functioning
|
||||
* as expected, which really shouln't happen.
|
||||
@ -590,7 +594,8 @@ static void i915_guc_submit(struct drm_i915_gem_request *rq)
|
||||
struct i915_guc_client *client = guc->execbuf_client;
|
||||
int b_ret;
|
||||
|
||||
guc_add_workqueue_item(client, rq);
|
||||
spin_lock(&client->wq_lock);
|
||||
guc_wq_item_append(client, rq);
|
||||
b_ret = guc_ring_doorbell(client);
|
||||
|
||||
client->submissions[engine_id] += 1;
|
||||
@ -600,6 +605,7 @@ static void i915_guc_submit(struct drm_i915_gem_request *rq)
|
||||
|
||||
guc->submissions[engine_id] += 1;
|
||||
guc->last_seqno[engine_id] = rq->fence.seqno;
|
||||
spin_unlock(&client->wq_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -680,7 +686,7 @@ guc_client_free(struct drm_i915_private *dev_priv,
|
||||
i915_vma_unpin_and_release(&client->vma);
|
||||
|
||||
if (client->ctx_index != GUC_INVALID_CTX_ID) {
|
||||
guc_fini_ctx_desc(guc, client);
|
||||
guc_ctx_desc_fini(guc, client);
|
||||
ida_simple_remove(&guc->ctx_ids, client->ctx_index);
|
||||
}
|
||||
|
||||
@ -733,8 +739,8 @@ static void guc_init_doorbell_hw(struct intel_guc *guc)
|
||||
/* Restore to original value */
|
||||
err = guc_update_doorbell_id(guc, client, db_id);
|
||||
if (err)
|
||||
DRM_ERROR("Failed to restore doorbell to %d, err %d\n",
|
||||
db_id, err);
|
||||
DRM_WARN("Failed to restore doorbell to %d, err %d\n",
|
||||
db_id, err);
|
||||
|
||||
/* Read back & verify all doorbell registers */
|
||||
for (i = 0; i < GUC_MAX_DOORBELLS; ++i)
|
||||
@ -790,6 +796,8 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
|
||||
/* We'll keep just the first (doorbell/proc) page permanently kmap'd. */
|
||||
client->vma = vma;
|
||||
client->client_base = kmap(i915_vma_first_page(vma));
|
||||
|
||||
spin_lock_init(&client->wq_lock);
|
||||
client->wq_offset = GUC_DB_SIZE;
|
||||
client->wq_size = GUC_WQ_SIZE;
|
||||
|
||||
@ -810,8 +818,8 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
|
||||
else
|
||||
client->proc_desc_offset = (GUC_DB_SIZE / 2);
|
||||
|
||||
guc_init_proc_desc(guc, client);
|
||||
guc_init_ctx_desc(guc, client);
|
||||
guc_proc_desc_init(guc, client);
|
||||
guc_ctx_desc_init(guc, client);
|
||||
if (guc_init_doorbell(guc, client, db_id))
|
||||
goto err;
|
||||
|
||||
@ -823,13 +831,11 @@ guc_client_alloc(struct drm_i915_private *dev_priv,
|
||||
return client;
|
||||
|
||||
err:
|
||||
DRM_ERROR("FAILED to create priority %u GuC client!\n", priority);
|
||||
|
||||
guc_client_free(dev_priv, client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void guc_create_log(struct intel_guc *guc)
|
||||
static void guc_log_create(struct intel_guc *guc)
|
||||
{
|
||||
struct i915_vma *vma;
|
||||
unsigned long offset;
|
||||
@ -869,7 +875,7 @@ static void guc_create_log(struct intel_guc *guc)
|
||||
guc->log_flags = (offset << GUC_LOG_BUF_ADDR_SHIFT) | flags;
|
||||
}
|
||||
|
||||
static void init_guc_policies(struct guc_policies *policies)
|
||||
static void guc_policies_init(struct guc_policies *policies)
|
||||
{
|
||||
struct guc_policy *policy;
|
||||
u32 p, i;
|
||||
@ -891,7 +897,7 @@ static void init_guc_policies(struct guc_policies *policies)
|
||||
policies->is_valid = 1;
|
||||
}
|
||||
|
||||
static void guc_create_ads(struct intel_guc *guc)
|
||||
static void guc_addon_create(struct intel_guc *guc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = guc_to_i915(guc);
|
||||
struct i915_vma *vma;
|
||||
@ -934,7 +940,7 @@ static void guc_create_ads(struct intel_guc *guc)
|
||||
|
||||
/* GuC scheduling policies */
|
||||
policies = (void *)ads + sizeof(struct guc_ads);
|
||||
init_guc_policies(policies);
|
||||
guc_policies_init(policies);
|
||||
|
||||
ads->scheduler_policies =
|
||||
i915_ggtt_offset(vma) + sizeof(struct guc_ads);
|
||||
@ -965,9 +971,11 @@ static void guc_create_ads(struct intel_guc *guc)
|
||||
*/
|
||||
int i915_guc_submission_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
const size_t ctxsize = sizeof(struct guc_context_desc);
|
||||
const size_t poolsize = GUC_MAX_GPU_CONTEXTS * ctxsize;
|
||||
const size_t gemsize = round_up(poolsize, PAGE_SIZE);
|
||||
struct intel_guc *guc = &dev_priv->guc;
|
||||
struct i915_vma *vma;
|
||||
u32 size;
|
||||
|
||||
/* Wipe bitmap & delete client in case of reinitialisation */
|
||||
bitmap_clear(guc->doorbell_bitmap, 0, GUC_MAX_DOORBELLS);
|
||||
@ -979,15 +987,14 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
|
||||
if (guc->ctx_pool_vma)
|
||||
return 0; /* already allocated */
|
||||
|
||||
size = PAGE_ALIGN(GUC_MAX_GPU_CONTEXTS*sizeof(struct guc_context_desc));
|
||||
vma = guc_allocate_vma(guc, size);
|
||||
vma = guc_allocate_vma(guc, gemsize);
|
||||
if (IS_ERR(vma))
|
||||
return PTR_ERR(vma);
|
||||
|
||||
guc->ctx_pool_vma = vma;
|
||||
ida_init(&guc->ctx_ids);
|
||||
guc_create_log(guc);
|
||||
guc_create_ads(guc);
|
||||
guc_log_create(guc);
|
||||
guc_addon_create(guc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -997,6 +1004,7 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
|
||||
struct intel_guc *guc = &dev_priv->guc;
|
||||
struct i915_guc_client *client;
|
||||
struct intel_engine_cs *engine;
|
||||
struct drm_i915_gem_request *request;
|
||||
|
||||
/* client for execbuf submission */
|
||||
client = guc_client_alloc(dev_priv,
|
||||
@ -1004,7 +1012,7 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
|
||||
GUC_CTX_PRIORITY_KMD_NORMAL,
|
||||
dev_priv->kernel_context);
|
||||
if (!client) {
|
||||
DRM_ERROR("Failed to create execbuf guc_client\n");
|
||||
DRM_ERROR("Failed to create normal GuC client!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -1013,9 +1021,17 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
|
||||
guc_init_doorbell_hw(guc);
|
||||
|
||||
/* Take over from manual control of ELSP (execlists) */
|
||||
for_each_engine(engine, dev_priv)
|
||||
for_each_engine(engine, dev_priv) {
|
||||
engine->submit_request = i915_guc_submit;
|
||||
|
||||
/* Replay the current set of previously submitted requests */
|
||||
list_for_each_entry(request, &engine->request_list, link) {
|
||||
client->wq_rsvd += sizeof(struct guc_wq_item);
|
||||
if (i915_sw_fence_done(&request->submit))
|
||||
i915_guc_submit(request);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ void gen6_disable_rps_interrupts(struct drm_i915_private *dev_priv)
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
dev_priv->rps.interrupts_enabled = false;
|
||||
|
||||
I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
|
||||
I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0u));
|
||||
|
||||
__gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
|
||||
I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
|
||||
@ -2497,57 +2497,52 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
|
||||
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
|
||||
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
|
||||
char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
|
||||
int ret;
|
||||
|
||||
kobject_uevent_env(kobj, KOBJ_CHANGE, error_event);
|
||||
|
||||
DRM_DEBUG_DRIVER("resetting chip\n");
|
||||
kobject_uevent_env(kobj, KOBJ_CHANGE, reset_event);
|
||||
|
||||
/*
|
||||
* Note that there's only one work item which does gpu resets, so we
|
||||
* need not worry about concurrent gpu resets potentially incrementing
|
||||
* error->reset_counter twice. We only need to take care of another
|
||||
* racing irq/hangcheck declaring the gpu dead for a second time. A
|
||||
* quick check for that is good enough: schedule_work ensures the
|
||||
* correct ordering between hang detection and this work item, and since
|
||||
* the reset in-progress bit is only ever set by code outside of this
|
||||
* work we don't need to worry about any other races.
|
||||
* 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.
|
||||
*/
|
||||
if (i915_reset_in_progress(&dev_priv->gpu_error)) {
|
||||
DRM_DEBUG_DRIVER("resetting chip\n");
|
||||
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_runtime_pm_get(dev_priv);
|
||||
intel_prepare_reset(dev_priv);
|
||||
|
||||
do {
|
||||
/*
|
||||
* All state reset _must_ be completed before we update the
|
||||
* reset counter, for otherwise waiters might miss the reset
|
||||
* pending state and not properly drop locks, resulting in
|
||||
* deadlocks with the reset work.
|
||||
*/
|
||||
ret = i915_reset(dev_priv);
|
||||
if (mutex_trylock(&dev_priv->drm.struct_mutex)) {
|
||||
i915_reset(dev_priv);
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
}
|
||||
|
||||
intel_finish_reset(dev_priv);
|
||||
/* We need to wait for anyone holding the lock to wakeup */
|
||||
} while (wait_on_bit_timeout(&dev_priv->gpu_error.flags,
|
||||
I915_RESET_IN_PROGRESS,
|
||||
TASK_UNINTERRUPTIBLE,
|
||||
HZ));
|
||||
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
intel_finish_reset(dev_priv);
|
||||
intel_runtime_pm_put(dev_priv);
|
||||
|
||||
if (ret == 0)
|
||||
kobject_uevent_env(kobj,
|
||||
KOBJ_CHANGE, reset_done_event);
|
||||
if (!test_bit(I915_WEDGED, &dev_priv->gpu_error.flags))
|
||||
kobject_uevent_env(kobj,
|
||||
KOBJ_CHANGE, reset_done_event);
|
||||
|
||||
/*
|
||||
* Note: The wake_up also serves as a memory barrier so that
|
||||
* waiters see the update value of the reset counter atomic_t.
|
||||
*/
|
||||
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
||||
}
|
||||
/*
|
||||
* Note: The wake_up also serves as a memory barrier so that
|
||||
* waiters see the updated value of the dev_priv->gpu_error.
|
||||
*/
|
||||
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
||||
}
|
||||
|
||||
static void i915_report_and_clear_eir(struct drm_i915_private *dev_priv)
|
||||
@ -2666,25 +2661,26 @@ void i915_handle_error(struct drm_i915_private *dev_priv,
|
||||
i915_capture_error_state(dev_priv, engine_mask, error_msg);
|
||||
i915_report_and_clear_eir(dev_priv);
|
||||
|
||||
if (engine_mask) {
|
||||
atomic_or(I915_RESET_IN_PROGRESS_FLAG,
|
||||
&dev_priv->gpu_error.reset_counter);
|
||||
if (!engine_mask)
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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 serves as the required memory barrier to
|
||||
* ensure that the waiters see the updated value of the reset
|
||||
* counter atomic_t.
|
||||
*/
|
||||
i915_error_wake_up(dev_priv);
|
||||
}
|
||||
if (test_and_set_bit(I915_RESET_IN_PROGRESS,
|
||||
&dev_priv->gpu_error.flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@ -2835,10 +2831,10 @@ semaphore_wait_to_signaller_ring(struct intel_engine_cs *engine, u32 ipehr,
|
||||
}
|
||||
}
|
||||
|
||||
DRM_ERROR("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n",
|
||||
engine->id, ipehr, offset);
|
||||
DRM_DEBUG_DRIVER("No signaller ring found for ring %i, ipehr 0x%08x, offset 0x%016llx\n",
|
||||
engine->id, ipehr, offset);
|
||||
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static struct intel_engine_cs *
|
||||
@ -2926,6 +2922,9 @@ static int semaphore_passed(struct intel_engine_cs *engine)
|
||||
if (signaller == NULL)
|
||||
return -1;
|
||||
|
||||
if (IS_ERR(signaller))
|
||||
return 0;
|
||||
|
||||
/* Prevent pathological recursion due to driver bugs */
|
||||
if (signaller->hangcheck.deadlock >= I915_NUM_ENGINES)
|
||||
return -1;
|
||||
@ -3079,6 +3078,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
|
||||
bool busy = intel_engine_has_waiter(engine);
|
||||
u64 acthd;
|
||||
u32 seqno;
|
||||
u32 submit;
|
||||
|
||||
semaphore_clear_deadlocks(dev_priv);
|
||||
|
||||
@ -3094,14 +3094,11 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
|
||||
|
||||
acthd = intel_engine_get_active_head(engine);
|
||||
seqno = intel_engine_get_seqno(engine);
|
||||
submit = READ_ONCE(engine->last_submitted_seqno);
|
||||
|
||||
if (engine->hangcheck.seqno == seqno) {
|
||||
if (!intel_engine_is_active(engine)) {
|
||||
if (i915_seqno_passed(seqno, submit)) {
|
||||
engine->hangcheck.action = HANGCHECK_IDLE;
|
||||
if (busy) {
|
||||
/* Safeguard against driver failure */
|
||||
engine->hangcheck.score += BUSY;
|
||||
}
|
||||
} else {
|
||||
/* We always increment the hangcheck score
|
||||
* if the engine is busy and still processing
|
||||
@ -3167,6 +3164,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
|
||||
|
||||
if (hung) {
|
||||
char msg[80];
|
||||
unsigned int tmp;
|
||||
int len;
|
||||
|
||||
/* If some rings hung but others were still busy, only
|
||||
@ -3176,7 +3174,7 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
|
||||
hung &= ~stuck;
|
||||
len = scnprintf(msg, sizeof(msg),
|
||||
"%s on ", stuck == hung ? "No progress" : "Hang");
|
||||
for_each_engine_masked(engine, dev_priv, hung)
|
||||
for_each_engine_masked(engine, dev_priv, hung, tmp)
|
||||
len += scnprintf(msg + len, sizeof(msg) - len,
|
||||
"%s, ", engine->name);
|
||||
msg[len-2] = '\0';
|
||||
@ -4502,7 +4500,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
|
||||
dev_priv->rps.pm_intr_keep |= GEN6_PM_RP_UP_EI_EXPIRED;
|
||||
|
||||
if (INTEL_INFO(dev_priv)->gen >= 8)
|
||||
dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
|
||||
dev_priv->rps.pm_intr_keep |= GEN8_PMINTR_REDIRECT_TO_GUC;
|
||||
|
||||
INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
|
||||
i915_hangcheck_elapsed);
|
||||
|
@ -54,208 +54,216 @@
|
||||
#define CHV_COLORS \
|
||||
.color = { .degamma_lut_size = 65, .gamma_lut_size = 257 }
|
||||
|
||||
#define GEN2_FEATURES \
|
||||
.gen = 2, .num_pipes = 1, \
|
||||
.has_overlay = 1, .overlay_needs_physical = 1, \
|
||||
.has_gmch_display = 1, \
|
||||
.hws_needs_physical = 1, \
|
||||
.ring_mask = RENDER_RING, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_i830_info = {
|
||||
.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN2_FEATURES,
|
||||
.is_mobile = 1, .cursor_needs_physical = 1,
|
||||
.num_pipes = 2, /* legal, last one wins */
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_845g_info = {
|
||||
.gen = 2, .num_pipes = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN2_FEATURES,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i85x_info = {
|
||||
.gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2,
|
||||
GEN2_FEATURES,
|
||||
.is_i85x = 1, .is_mobile = 1,
|
||||
.num_pipes = 2, /* legal, last one wins */
|
||||
.cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i865g_info = {
|
||||
.gen = 2, .num_pipes = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN2_FEATURES,
|
||||
};
|
||||
|
||||
#define GEN3_FEATURES \
|
||||
.gen = 3, .num_pipes = 2, \
|
||||
.has_gmch_display = 1, \
|
||||
.ring_mask = RENDER_RING, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_i915g_info = {
|
||||
.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
|
||||
GEN3_FEATURES,
|
||||
.is_i915g = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i915gm_info = {
|
||||
.gen = 3, .is_mobile = 1, .num_pipes = 2,
|
||||
GEN3_FEATURES,
|
||||
.is_mobile = 1,
|
||||
.cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i945g_info = {
|
||||
.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
|
||||
GEN3_FEATURES,
|
||||
.has_hotplug = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
static const struct intel_device_info intel_i945gm_info = {
|
||||
.gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
|
||||
GEN3_FEATURES,
|
||||
.is_i945gm = 1, .is_mobile = 1,
|
||||
.has_hotplug = 1, .cursor_needs_physical = 1,
|
||||
.has_overlay = 1, .overlay_needs_physical = 1,
|
||||
.supports_tv = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
|
||||
#define GEN4_FEATURES \
|
||||
.gen = 4, .num_pipes = 2, \
|
||||
.has_hotplug = 1, \
|
||||
.has_gmch_display = 1, \
|
||||
.ring_mask = RENDER_RING, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_i965g_info = {
|
||||
.gen = 4, .is_broadwater = 1, .num_pipes = 2,
|
||||
.has_hotplug = 1,
|
||||
GEN4_FEATURES,
|
||||
.is_broadwater = 1,
|
||||
.has_overlay = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_i965gm_info = {
|
||||
.gen = 4, .is_crestline = 1, .num_pipes = 2,
|
||||
.is_mobile = 1, .has_fbc = 1, .has_hotplug = 1,
|
||||
GEN4_FEATURES,
|
||||
.is_crestline = 1,
|
||||
.is_mobile = 1, .has_fbc = 1,
|
||||
.has_overlay = 1,
|
||||
.supports_tv = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
.hws_needs_physical = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g33_info = {
|
||||
.gen = 3, .is_g33 = 1, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
GEN3_FEATURES,
|
||||
.is_g33 = 1,
|
||||
.has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_g45_info = {
|
||||
.gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
|
||||
.has_pipe_cxsr = 1, .has_hotplug = 1,
|
||||
GEN4_FEATURES,
|
||||
.is_g4x = 1,
|
||||
.has_pipe_cxsr = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_gm45_info = {
|
||||
.gen = 4, .is_g4x = 1, .num_pipes = 2,
|
||||
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1,
|
||||
.has_pipe_cxsr = 1, .has_hotplug = 1,
|
||||
GEN4_FEATURES,
|
||||
.is_g4x = 1,
|
||||
.is_mobile = 1, .has_fbc = 1,
|
||||
.has_pipe_cxsr = 1,
|
||||
.supports_tv = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_pineview_info = {
|
||||
.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
GEN3_FEATURES,
|
||||
.is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
|
||||
.has_hotplug = 1,
|
||||
.has_overlay = 1,
|
||||
.ring_mask = RENDER_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
};
|
||||
|
||||
#define GEN5_FEATURES \
|
||||
.gen = 5, .num_pipes = 2, \
|
||||
.has_hotplug = 1, \
|
||||
.has_gmbus_irq = 1, \
|
||||
.ring_mask = RENDER_RING | BSD_RING, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_ironlake_d_info = {
|
||||
.gen = 5, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN5_FEATURES,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ironlake_m_info = {
|
||||
.gen = 5, .is_mobile = 1, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN5_FEATURES,
|
||||
.is_mobile = 1,
|
||||
};
|
||||
|
||||
#define GEN6_FEATURES \
|
||||
.gen = 6, .num_pipes = 2, \
|
||||
.has_hotplug = 1, \
|
||||
.has_fbc = 1, \
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
|
||||
.has_llc = 1, \
|
||||
.has_rc6 = 1, \
|
||||
.has_rc6p = 1, \
|
||||
.has_gmbus_irq = 1, \
|
||||
.has_hw_contexts = 1, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_d_info = {
|
||||
.gen = 6, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
|
||||
.has_llc = 1,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN6_FEATURES,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_sandybridge_m_info = {
|
||||
.gen = 6, .is_mobile = 1, .num_pipes = 2,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_fbc = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING,
|
||||
.has_llc = 1,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
GEN6_FEATURES,
|
||||
.is_mobile = 1,
|
||||
};
|
||||
|
||||
#define GEN7_FEATURES \
|
||||
.gen = 7, .num_pipes = 3, \
|
||||
.need_gfx_hws = 1, .has_hotplug = 1, \
|
||||
.has_hotplug = 1, \
|
||||
.has_fbc = 1, \
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
|
||||
.has_llc = 1, \
|
||||
.has_rc6 = 1, \
|
||||
.has_rc6p = 1, \
|
||||
.has_gmbus_irq = 1, \
|
||||
.has_hw_contexts = 1, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
IVB_CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_d_info = {
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
.has_l3_dpf = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_m_info = {
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
.is_mobile = 1,
|
||||
.has_l3_dpf = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_ivybridge_q_info = {
|
||||
GEN7_FEATURES,
|
||||
.is_ivybridge = 1,
|
||||
.num_pipes = 0, /* legal, last one wins */
|
||||
.has_l3_dpf = 1,
|
||||
};
|
||||
|
||||
#define VLV_FEATURES \
|
||||
.gen = 7, .num_pipes = 2, \
|
||||
.need_gfx_hws = 1, .has_hotplug = 1, \
|
||||
.has_psr = 1, \
|
||||
.has_runtime_pm = 1, \
|
||||
.has_rc6 = 1, \
|
||||
.has_gmbus_irq = 1, \
|
||||
.has_hw_contexts = 1, \
|
||||
.has_gmch_display = 1, \
|
||||
.has_hotplug = 1, \
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE, \
|
||||
GEN_DEFAULT_PIPEOFFSETS, \
|
||||
CURSOR_OFFSETS
|
||||
|
||||
static const struct intel_device_info intel_valleyview_m_info = {
|
||||
VLV_FEATURES,
|
||||
.is_valleyview = 1,
|
||||
.is_mobile = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_valleyview_d_info = {
|
||||
static const struct intel_device_info intel_valleyview_info = {
|
||||
VLV_FEATURES,
|
||||
.is_valleyview = 1,
|
||||
};
|
||||
@ -264,54 +272,50 @@ static const struct intel_device_info intel_valleyview_d_info = {
|
||||
GEN7_FEATURES, \
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, \
|
||||
.has_ddi = 1, \
|
||||
.has_fpga_dbg = 1
|
||||
.has_fpga_dbg = 1, \
|
||||
.has_psr = 1, \
|
||||
.has_resource_streamer = 1, \
|
||||
.has_dp_mst = 1, \
|
||||
.has_rc6p = 0 /* RC6p removed-by HSW */, \
|
||||
.has_runtime_pm = 1
|
||||
|
||||
static const struct intel_device_info intel_haswell_d_info = {
|
||||
static const struct intel_device_info intel_haswell_info = {
|
||||
HSW_FEATURES,
|
||||
.is_haswell = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_haswell_m_info = {
|
||||
HSW_FEATURES,
|
||||
.is_haswell = 1,
|
||||
.is_mobile = 1,
|
||||
.has_l3_dpf = 1,
|
||||
};
|
||||
|
||||
#define BDW_FEATURES \
|
||||
HSW_FEATURES, \
|
||||
BDW_COLORS
|
||||
BDW_COLORS, \
|
||||
.has_logical_ring_contexts = 1
|
||||
|
||||
static const struct intel_device_info intel_broadwell_d_info = {
|
||||
static const struct intel_device_info intel_broadwell_info = {
|
||||
BDW_FEATURES,
|
||||
.gen = 8,
|
||||
.is_broadwell = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_m_info = {
|
||||
BDW_FEATURES,
|
||||
.gen = 8, .is_mobile = 1,
|
||||
.is_broadwell = 1,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt3d_info = {
|
||||
static const struct intel_device_info intel_broadwell_gt3_info = {
|
||||
BDW_FEATURES,
|
||||
.gen = 8,
|
||||
.is_broadwell = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broadwell_gt3m_info = {
|
||||
BDW_FEATURES,
|
||||
.gen = 8, .is_mobile = 1,
|
||||
.is_broadwell = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_cherryview_info = {
|
||||
.gen = 8, .num_pipes = 3,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_hotplug = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
|
||||
.is_cherryview = 1,
|
||||
.has_psr = 1,
|
||||
.has_runtime_pm = 1,
|
||||
.has_resource_streamer = 1,
|
||||
.has_rc6 = 1,
|
||||
.has_gmbus_irq = 1,
|
||||
.has_hw_contexts = 1,
|
||||
.has_logical_ring_contexts = 1,
|
||||
.has_gmch_display = 1,
|
||||
.display_mmio_offset = VLV_DISPLAY_BASE,
|
||||
GEN_CHV_PIPEOFFSETS,
|
||||
CURSOR_OFFSETS,
|
||||
@ -322,25 +326,41 @@ static const struct intel_device_info intel_skylake_info = {
|
||||
BDW_FEATURES,
|
||||
.is_skylake = 1,
|
||||
.gen = 9,
|
||||
.has_csr = 1,
|
||||
.has_guc = 1,
|
||||
.ddb_size = 896,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_skylake_gt3_info = {
|
||||
BDW_FEATURES,
|
||||
.is_skylake = 1,
|
||||
.gen = 9,
|
||||
.has_csr = 1,
|
||||
.has_guc = 1,
|
||||
.ddb_size = 896,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_broxton_info = {
|
||||
.is_broxton = 1,
|
||||
.gen = 9,
|
||||
.need_gfx_hws = 1, .has_hotplug = 1,
|
||||
.has_hotplug = 1,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
|
||||
.num_pipes = 3,
|
||||
.has_ddi = 1,
|
||||
.has_fpga_dbg = 1,
|
||||
.has_fbc = 1,
|
||||
.has_runtime_pm = 1,
|
||||
.has_pooled_eu = 0,
|
||||
.has_csr = 1,
|
||||
.has_resource_streamer = 1,
|
||||
.has_rc6 = 1,
|
||||
.has_dp_mst = 1,
|
||||
.has_gmbus_irq = 1,
|
||||
.has_hw_contexts = 1,
|
||||
.has_logical_ring_contexts = 1,
|
||||
.has_guc = 1,
|
||||
.ddb_size = 512,
|
||||
GEN_DEFAULT_PIPEOFFSETS,
|
||||
IVB_CURSOR_OFFSETS,
|
||||
BDW_COLORS,
|
||||
@ -350,12 +370,18 @@ static const struct intel_device_info intel_kabylake_info = {
|
||||
BDW_FEATURES,
|
||||
.is_kabylake = 1,
|
||||
.gen = 9,
|
||||
.has_csr = 1,
|
||||
.has_guc = 1,
|
||||
.ddb_size = 896,
|
||||
};
|
||||
|
||||
static const struct intel_device_info intel_kabylake_gt3_info = {
|
||||
BDW_FEATURES,
|
||||
.is_kabylake = 1,
|
||||
.gen = 9,
|
||||
.has_csr = 1,
|
||||
.has_guc = 1,
|
||||
.ddb_size = 896,
|
||||
.ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING,
|
||||
};
|
||||
|
||||
@ -387,14 +413,10 @@ static const struct pci_device_id pciidlist[] = {
|
||||
INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */
|
||||
INTEL_IVB_M_IDS(&intel_ivybridge_m_info),
|
||||
INTEL_IVB_D_IDS(&intel_ivybridge_d_info),
|
||||
INTEL_HSW_D_IDS(&intel_haswell_d_info),
|
||||
INTEL_HSW_M_IDS(&intel_haswell_m_info),
|
||||
INTEL_VLV_M_IDS(&intel_valleyview_m_info),
|
||||
INTEL_VLV_D_IDS(&intel_valleyview_d_info),
|
||||
INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info),
|
||||
INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info),
|
||||
INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info),
|
||||
INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info),
|
||||
INTEL_HSW_IDS(&intel_haswell_info),
|
||||
INTEL_VLV_IDS(&intel_valleyview_info),
|
||||
INTEL_BDW_GT12_IDS(&intel_broadwell_info),
|
||||
INTEL_BDW_GT3_IDS(&intel_broadwell_gt3_info),
|
||||
INTEL_CHV_IDS(&intel_cherryview_info),
|
||||
INTEL_SKL_GT1_IDS(&intel_skylake_info),
|
||||
INTEL_SKL_GT2_IDS(&intel_skylake_info),
|
||||
|
@ -7067,7 +7067,7 @@ enum {
|
||||
#define VLV_RCEDATA _MMIO(0xA0BC)
|
||||
#define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0)
|
||||
#define GEN6_PMINTRMSK _MMIO(0xA168)
|
||||
#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31)
|
||||
#define GEN8_PMINTR_REDIRECT_TO_GUC (1<<31)
|
||||
#define GEN8_MISC_CTRL0 _MMIO(0xA180)
|
||||
#define VLV_PWRDWNUPCTL _MMIO(0xA294)
|
||||
#define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4)
|
||||
@ -7123,6 +7123,15 @@ enum {
|
||||
|
||||
#define GEN6_PCODE_MAILBOX _MMIO(0x138124)
|
||||
#define GEN6_PCODE_READY (1<<31)
|
||||
#define GEN6_PCODE_ERROR_MASK 0xFF
|
||||
#define GEN6_PCODE_SUCCESS 0x0
|
||||
#define GEN6_PCODE_ILLEGAL_CMD 0x1
|
||||
#define GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE 0x2
|
||||
#define GEN6_PCODE_TIMEOUT 0x3
|
||||
#define GEN6_PCODE_UNIMPLEMENTED_CMD 0xFF
|
||||
#define GEN7_PCODE_TIMEOUT 0x2
|
||||
#define GEN7_PCODE_ILLEGAL_DATA 0x3
|
||||
#define GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE 0x10
|
||||
#define GEN6_PCODE_WRITE_RC6VIDS 0x4
|
||||
#define GEN6_PCODE_READ_RC6VIDS 0x5
|
||||
#define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5)
|
||||
@ -7144,6 +7153,10 @@ enum {
|
||||
#define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17
|
||||
#define DISPLAY_IPS_CONTROL 0x19
|
||||
#define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A
|
||||
#define GEN9_PCODE_SAGV_CONTROL 0x21
|
||||
#define GEN9_SAGV_DISABLE 0x0
|
||||
#define GEN9_SAGV_IS_DISABLED 0x1
|
||||
#define GEN9_SAGV_ENABLE 0x3
|
||||
#define GEN6_PCODE_DATA _MMIO(0x138128)
|
||||
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
|
||||
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
|
||||
|
@ -63,6 +63,7 @@ static void i915_restore_display(struct drm_device *dev)
|
||||
int i915_save_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int i;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
@ -70,7 +71,7 @@ int i915_save_state(struct drm_device *dev)
|
||||
i915_save_display(dev);
|
||||
|
||||
if (IS_GEN4(dev))
|
||||
pci_read_config_word(dev->pdev, GCDGMBUS,
|
||||
pci_read_config_word(pdev, GCDGMBUS,
|
||||
&dev_priv->regfile.saveGCDGMBUS);
|
||||
|
||||
/* Cache mode state */
|
||||
@ -108,6 +109,7 @@ int i915_save_state(struct drm_device *dev)
|
||||
int i915_restore_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
int i;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
@ -115,7 +117,7 @@ int i915_restore_state(struct drm_device *dev)
|
||||
i915_gem_restore_fences(dev);
|
||||
|
||||
if (IS_GEN4(dev))
|
||||
pci_write_config_word(dev->pdev, GCDGMBUS,
|
||||
pci_write_config_word(pdev, GCDGMBUS,
|
||||
dev_priv->regfile.saveGCDGMBUS);
|
||||
i915_restore_display(dev);
|
||||
|
||||
|
362
drivers/gpu/drm/i915/i915_sw_fence.c
Normal file
362
drivers/gpu/drm/i915/i915_sw_fence.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* (C) Copyright 2016 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; version 2
|
||||
* of the License.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/fence.h>
|
||||
#include <linux/reservation.h>
|
||||
|
||||
#include "i915_sw_fence.h"
|
||||
|
||||
static DEFINE_SPINLOCK(i915_sw_fence_lock);
|
||||
|
||||
static int __i915_sw_fence_notify(struct i915_sw_fence *fence,
|
||||
enum i915_sw_fence_notify state)
|
||||
{
|
||||
i915_sw_fence_notify_t fn;
|
||||
|
||||
fn = (i915_sw_fence_notify_t)(fence->flags & I915_SW_FENCE_MASK);
|
||||
return fn(fence, state);
|
||||
}
|
||||
|
||||
static void i915_sw_fence_free(struct kref *kref)
|
||||
{
|
||||
struct i915_sw_fence *fence = container_of(kref, typeof(*fence), kref);
|
||||
|
||||
WARN_ON(atomic_read(&fence->pending) > 0);
|
||||
|
||||
if (fence->flags & I915_SW_FENCE_MASK)
|
||||
__i915_sw_fence_notify(fence, FENCE_FREE);
|
||||
else
|
||||
kfree(fence);
|
||||
}
|
||||
|
||||
static void i915_sw_fence_put(struct i915_sw_fence *fence)
|
||||
{
|
||||
kref_put(&fence->kref, i915_sw_fence_free);
|
||||
}
|
||||
|
||||
static struct i915_sw_fence *i915_sw_fence_get(struct i915_sw_fence *fence)
|
||||
{
|
||||
kref_get(&fence->kref);
|
||||
return fence;
|
||||
}
|
||||
|
||||
static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
|
||||
struct list_head *continuation)
|
||||
{
|
||||
wait_queue_head_t *x = &fence->wait;
|
||||
wait_queue_t *pos, *next;
|
||||
unsigned long flags;
|
||||
|
||||
atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */
|
||||
|
||||
/*
|
||||
* To prevent unbounded recursion as we traverse the graph of
|
||||
* i915_sw_fences, we move the task_list from this, the next ready
|
||||
* fence, to the tail of the original fence's task_list
|
||||
* (and so added to the list to be woken).
|
||||
*/
|
||||
|
||||
spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation);
|
||||
if (continuation) {
|
||||
list_for_each_entry_safe(pos, next, &x->task_list, task_list) {
|
||||
if (pos->func == autoremove_wake_function)
|
||||
pos->func(pos, TASK_NORMAL, 0, continuation);
|
||||
else
|
||||
list_move_tail(&pos->task_list, continuation);
|
||||
}
|
||||
} else {
|
||||
LIST_HEAD(extra);
|
||||
|
||||
do {
|
||||
list_for_each_entry_safe(pos, next,
|
||||
&x->task_list, task_list)
|
||||
pos->func(pos, TASK_NORMAL, 0, &extra);
|
||||
|
||||
if (list_empty(&extra))
|
||||
break;
|
||||
|
||||
list_splice_tail_init(&extra, &x->task_list);
|
||||
} while (1);
|
||||
}
|
||||
spin_unlock_irqrestore(&x->lock, flags);
|
||||
}
|
||||
|
||||
static void __i915_sw_fence_complete(struct i915_sw_fence *fence,
|
||||
struct list_head *continuation)
|
||||
{
|
||||
if (!atomic_dec_and_test(&fence->pending))
|
||||
return;
|
||||
|
||||
if (fence->flags & I915_SW_FENCE_MASK &&
|
||||
__i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE)
|
||||
return;
|
||||
|
||||
__i915_sw_fence_wake_up_all(fence, continuation);
|
||||
}
|
||||
|
||||
static void i915_sw_fence_complete(struct i915_sw_fence *fence)
|
||||
{
|
||||
if (WARN_ON(i915_sw_fence_done(fence)))
|
||||
return;
|
||||
|
||||
__i915_sw_fence_complete(fence, NULL);
|
||||
}
|
||||
|
||||
static void i915_sw_fence_await(struct i915_sw_fence *fence)
|
||||
{
|
||||
WARN_ON(atomic_inc_return(&fence->pending) <= 1);
|
||||
}
|
||||
|
||||
void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn)
|
||||
{
|
||||
BUG_ON((unsigned long)fn & ~I915_SW_FENCE_MASK);
|
||||
|
||||
init_waitqueue_head(&fence->wait);
|
||||
kref_init(&fence->kref);
|
||||
atomic_set(&fence->pending, 1);
|
||||
fence->flags = (unsigned long)fn;
|
||||
}
|
||||
|
||||
void i915_sw_fence_commit(struct i915_sw_fence *fence)
|
||||
{
|
||||
i915_sw_fence_complete(fence);
|
||||
i915_sw_fence_put(fence);
|
||||
}
|
||||
|
||||
static int i915_sw_fence_wake(wait_queue_t *wq, unsigned mode, int flags, void *key)
|
||||
{
|
||||
list_del(&wq->task_list);
|
||||
__i915_sw_fence_complete(wq->private, key);
|
||||
i915_sw_fence_put(wq->private);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
|
||||
const struct i915_sw_fence * const signaler)
|
||||
{
|
||||
wait_queue_t *wq;
|
||||
|
||||
if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
|
||||
return false;
|
||||
|
||||
if (fence == signaler)
|
||||
return true;
|
||||
|
||||
list_for_each_entry(wq, &fence->wait.task_list, task_list) {
|
||||
if (wq->func != i915_sw_fence_wake)
|
||||
continue;
|
||||
|
||||
if (__i915_sw_fence_check_if_after(wq->private, signaler))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence)
|
||||
{
|
||||
wait_queue_t *wq;
|
||||
|
||||
if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
|
||||
return;
|
||||
|
||||
list_for_each_entry(wq, &fence->wait.task_list, task_list) {
|
||||
if (wq->func != i915_sw_fence_wake)
|
||||
continue;
|
||||
|
||||
__i915_sw_fence_clear_checked_bit(wq->private);
|
||||
}
|
||||
}
|
||||
|
||||
static bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
|
||||
const struct i915_sw_fence * const signaler)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool err;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_I915_SW_FENCE_CHECK_DAG))
|
||||
return false;
|
||||
|
||||
spin_lock_irqsave(&i915_sw_fence_lock, flags);
|
||||
err = __i915_sw_fence_check_if_after(fence, signaler);
|
||||
__i915_sw_fence_clear_checked_bit(fence);
|
||||
spin_unlock_irqrestore(&i915_sw_fence_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
|
||||
struct i915_sw_fence *signaler,
|
||||
wait_queue_t *wq)
|
||||
{
|
||||
unsigned long flags;
|
||||
int pending;
|
||||
|
||||
if (i915_sw_fence_done(signaler))
|
||||
return 0;
|
||||
|
||||
/* The dependency graph must be acyclic. */
|
||||
if (unlikely(i915_sw_fence_check_if_after(fence, signaler)))
|
||||
return -EINVAL;
|
||||
|
||||
INIT_LIST_HEAD(&wq->task_list);
|
||||
wq->flags = 0;
|
||||
wq->func = i915_sw_fence_wake;
|
||||
wq->private = i915_sw_fence_get(fence);
|
||||
|
||||
i915_sw_fence_await(fence);
|
||||
|
||||
spin_lock_irqsave(&signaler->wait.lock, flags);
|
||||
if (likely(!i915_sw_fence_done(signaler))) {
|
||||
__add_wait_queue_tail(&signaler->wait, wq);
|
||||
pending = 1;
|
||||
} else {
|
||||
i915_sw_fence_wake(wq, 0, 0, NULL);
|
||||
pending = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&signaler->wait.lock, flags);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
struct dma_fence_cb {
|
||||
struct fence_cb base;
|
||||
struct i915_sw_fence *fence;
|
||||
struct fence *dma;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
static void timer_i915_sw_fence_wake(unsigned long data)
|
||||
{
|
||||
struct dma_fence_cb *cb = (struct dma_fence_cb *)data;
|
||||
|
||||
printk(KERN_WARNING "asynchronous wait on fence %s:%s:%x timed out\n",
|
||||
cb->dma->ops->get_driver_name(cb->dma),
|
||||
cb->dma->ops->get_timeline_name(cb->dma),
|
||||
cb->dma->seqno);
|
||||
fence_put(cb->dma);
|
||||
cb->dma = NULL;
|
||||
|
||||
i915_sw_fence_commit(cb->fence);
|
||||
cb->timer.function = NULL;
|
||||
}
|
||||
|
||||
static void dma_i915_sw_fence_wake(struct fence *dma, struct fence_cb *data)
|
||||
{
|
||||
struct dma_fence_cb *cb = container_of(data, typeof(*cb), base);
|
||||
|
||||
del_timer_sync(&cb->timer);
|
||||
if (cb->timer.function)
|
||||
i915_sw_fence_commit(cb->fence);
|
||||
fence_put(cb->dma);
|
||||
|
||||
kfree(cb);
|
||||
}
|
||||
|
||||
int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
|
||||
struct fence *dma,
|
||||
unsigned long timeout,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct dma_fence_cb *cb;
|
||||
int ret;
|
||||
|
||||
if (fence_is_signaled(dma))
|
||||
return 0;
|
||||
|
||||
cb = kmalloc(sizeof(*cb), gfp);
|
||||
if (!cb) {
|
||||
if (!gfpflags_allow_blocking(gfp))
|
||||
return -ENOMEM;
|
||||
|
||||
return fence_wait(dma, false);
|
||||
}
|
||||
|
||||
cb->fence = i915_sw_fence_get(fence);
|
||||
i915_sw_fence_await(fence);
|
||||
|
||||
cb->dma = NULL;
|
||||
__setup_timer(&cb->timer,
|
||||
timer_i915_sw_fence_wake, (unsigned long)cb,
|
||||
TIMER_IRQSAFE);
|
||||
if (timeout) {
|
||||
cb->dma = fence_get(dma);
|
||||
mod_timer(&cb->timer, round_jiffies_up(jiffies + timeout));
|
||||
}
|
||||
|
||||
ret = fence_add_callback(dma, &cb->base, dma_i915_sw_fence_wake);
|
||||
if (ret == 0) {
|
||||
ret = 1;
|
||||
} else {
|
||||
dma_i915_sw_fence_wake(dma, &cb->base);
|
||||
if (ret == -ENOENT) /* fence already signaled */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
|
||||
struct reservation_object *resv,
|
||||
const struct fence_ops *exclude,
|
||||
bool write,
|
||||
unsigned long timeout,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct fence *excl;
|
||||
int ret = 0, pending;
|
||||
|
||||
if (write) {
|
||||
struct fence **shared;
|
||||
unsigned int count, i;
|
||||
|
||||
ret = reservation_object_get_fences_rcu(resv,
|
||||
&excl, &count, &shared);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (shared[i]->ops == exclude)
|
||||
continue;
|
||||
|
||||
pending = i915_sw_fence_await_dma_fence(fence,
|
||||
shared[i],
|
||||
timeout,
|
||||
gfp);
|
||||
if (pending < 0) {
|
||||
ret = pending;
|
||||
break;
|
||||
}
|
||||
|
||||
ret |= pending;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
fence_put(shared[i]);
|
||||
kfree(shared);
|
||||
} else {
|
||||
excl = reservation_object_get_excl_rcu(resv);
|
||||
}
|
||||
|
||||
if (ret >= 0 && excl && excl->ops != exclude) {
|
||||
pending = i915_sw_fence_await_dma_fence(fence,
|
||||
excl,
|
||||
timeout,
|
||||
gfp);
|
||||
if (pending < 0)
|
||||
ret = pending;
|
||||
else
|
||||
ret |= pending;
|
||||
}
|
||||
|
||||
fence_put(excl);
|
||||
|
||||
return ret;
|
||||
}
|
65
drivers/gpu/drm/i915/i915_sw_fence.h
Normal file
65
drivers/gpu/drm/i915/i915_sw_fence.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* i915_sw_fence.h - library routines for N:M synchronisation points
|
||||
*
|
||||
* Copyright (C) 2016 Intel Corporation
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _I915_SW_FENCE_H_
|
||||
#define _I915_SW_FENCE_H_
|
||||
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/notifier.h> /* for NOTIFY_DONE */
|
||||
#include <linux/wait.h>
|
||||
|
||||
struct completion;
|
||||
struct fence;
|
||||
struct fence_ops;
|
||||
struct reservation_object;
|
||||
|
||||
struct i915_sw_fence {
|
||||
wait_queue_head_t wait;
|
||||
unsigned long flags;
|
||||
struct kref kref;
|
||||
atomic_t pending;
|
||||
};
|
||||
|
||||
#define I915_SW_FENCE_CHECKED_BIT 0 /* used internally for DAG checking */
|
||||
#define I915_SW_FENCE_PRIVATE_BIT 1 /* available for use by owner */
|
||||
#define I915_SW_FENCE_MASK (~3)
|
||||
|
||||
enum i915_sw_fence_notify {
|
||||
FENCE_COMPLETE,
|
||||
FENCE_FREE
|
||||
};
|
||||
|
||||
typedef int (*i915_sw_fence_notify_t)(struct i915_sw_fence *,
|
||||
enum i915_sw_fence_notify state);
|
||||
#define __i915_sw_fence_call __aligned(4)
|
||||
|
||||
void i915_sw_fence_init(struct i915_sw_fence *fence, i915_sw_fence_notify_t fn);
|
||||
void i915_sw_fence_commit(struct i915_sw_fence *fence);
|
||||
|
||||
int i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
|
||||
struct i915_sw_fence *after,
|
||||
wait_queue_t *wq);
|
||||
int i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
|
||||
struct fence *dma,
|
||||
unsigned long timeout,
|
||||
gfp_t gfp);
|
||||
int i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
|
||||
struct reservation_object *resv,
|
||||
const struct fence_ops *exclude,
|
||||
bool write,
|
||||
unsigned long timeout,
|
||||
gfp_t gfp);
|
||||
|
||||
static inline bool i915_sw_fence_done(const struct i915_sw_fence *fence)
|
||||
{
|
||||
return atomic_read(&fence->pending) < 0;
|
||||
}
|
||||
|
||||
#endif /* _I915_SW_FENCE_H_ */
|
@ -32,13 +32,16 @@
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drv.h"
|
||||
|
||||
#define dev_to_drm_minor(d) dev_get_drvdata((d))
|
||||
static inline struct drm_i915_private *kdev_minor_to_i915(struct device *kdev)
|
||||
{
|
||||
struct drm_minor *minor = dev_get_drvdata(kdev);
|
||||
return to_i915(minor->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 calc_residency(struct drm_device *dev,
|
||||
static u32 calc_residency(struct drm_i915_private *dev_priv,
|
||||
i915_reg_t reg)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
u64 raw_time; /* 32b value may overflow during fixed point math */
|
||||
u64 units = 128ULL, div = 100000ULL;
|
||||
u32 ret;
|
||||
@ -49,13 +52,13 @@ static u32 calc_residency(struct drm_device *dev,
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
|
||||
/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
|
||||
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_BROXTON(dev)) {
|
||||
} else if (IS_BROXTON(dev_priv)) {
|
||||
units = 1;
|
||||
div = 1200; /* 833.33ns */
|
||||
}
|
||||
@ -76,32 +79,32 @@ show_rc6_mask(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t
|
||||
show_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *dminor = dev_get_drvdata(kdev);
|
||||
u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 rc6_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *dminor = dev_to_drm_minor(kdev);
|
||||
u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 rc6p_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6p);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *dminor = dev_to_drm_minor(kdev);
|
||||
u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 rc6pp_residency = calc_residency(dev_priv, GEN6_GT_GFX_RC6pp);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_media_rc6_ms(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *dminor = dev_get_drvdata(kdev);
|
||||
u32 rc6_residency = calc_residency(dminor->dev, VLV_GT_MEDIA_RC6);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 rc6_residency = calc_residency(dev_priv, VLV_GT_MEDIA_RC6);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rc6_residency);
|
||||
}
|
||||
|
||||
@ -144,9 +147,9 @@ static struct attribute_group media_rc6_attr_group = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static int l3_access_valid(struct drm_device *dev, loff_t offset)
|
||||
static int l3_access_valid(struct drm_i915_private *dev_priv, loff_t offset)
|
||||
{
|
||||
if (!HAS_L3_DPF(dev))
|
||||
if (!HAS_L3_DPF(dev_priv))
|
||||
return -EPERM;
|
||||
|
||||
if (offset % 4 != 0)
|
||||
@ -163,22 +166,21 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_minor *dminor = dev_to_drm_minor(dev);
|
||||
struct drm_device *drm_dev = dminor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(drm_dev);
|
||||
struct device *kdev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
int slice = (int)(uintptr_t)attr->private;
|
||||
int ret;
|
||||
|
||||
count = round_down(count, 4);
|
||||
|
||||
ret = l3_access_valid(drm_dev, offset);
|
||||
ret = l3_access_valid(dev_priv, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
count = min_t(size_t, GEN7_L3LOG_SIZE - offset, count);
|
||||
|
||||
ret = i915_mutex_lock_interruptible(drm_dev);
|
||||
ret = i915_mutex_lock_interruptible(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -189,7 +191,7 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
|
||||
else
|
||||
memset(buf, 0, count);
|
||||
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -199,30 +201,29 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
|
||||
struct bin_attribute *attr, char *buf,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct drm_minor *dminor = dev_to_drm_minor(dev);
|
||||
struct drm_device *drm_dev = dminor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(drm_dev);
|
||||
struct device *kdev = kobj_to_dev(kobj);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct i915_gem_context *ctx;
|
||||
u32 *temp = NULL; /* Just here to make handling failures easy */
|
||||
int slice = (int)(uintptr_t)attr->private;
|
||||
int ret;
|
||||
|
||||
if (!HAS_HW_CONTEXTS(drm_dev))
|
||||
if (!HAS_HW_CONTEXTS(dev_priv))
|
||||
return -ENXIO;
|
||||
|
||||
ret = l3_access_valid(drm_dev, offset);
|
||||
ret = l3_access_valid(dev_priv, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i915_mutex_lock_interruptible(drm_dev);
|
||||
ret = i915_mutex_lock_interruptible(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev_priv->l3_parity.remap_info[slice]) {
|
||||
temp = kzalloc(GEN7_L3LOG_SIZE, GFP_KERNEL);
|
||||
if (!temp) {
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
@ -240,7 +241,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
|
||||
list_for_each_entry(ctx, &dev_priv->context_list, link)
|
||||
ctx->remap_slice |= (1<<slice);
|
||||
|
||||
mutex_unlock(&drm_dev->struct_mutex);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -266,9 +267,7 @@ static struct bin_attribute dpf_attrs_1 = {
|
||||
static ssize_t gt_act_freq_mhz_show(struct device *kdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
int ret;
|
||||
|
||||
intel_runtime_pm_get(dev_priv);
|
||||
@ -298,9 +297,7 @@ static ssize_t gt_act_freq_mhz_show(struct device *kdev,
|
||||
static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
intel_gpu_freq(dev_priv,
|
||||
@ -309,8 +306,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
|
||||
|
||||
static ssize_t gt_boost_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_i915_private *dev_priv = to_i915(minor->dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
intel_gpu_freq(dev_priv,
|
||||
@ -321,9 +317,7 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 val;
|
||||
ssize_t ret;
|
||||
|
||||
@ -346,9 +340,7 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev,
|
||||
static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
intel_gpu_freq(dev_priv,
|
||||
@ -357,9 +349,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
|
||||
|
||||
static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
intel_gpu_freq(dev_priv,
|
||||
@ -370,9 +360,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 val;
|
||||
ssize_t ret;
|
||||
|
||||
@ -418,9 +406,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
|
||||
|
||||
static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
intel_gpu_freq(dev_priv,
|
||||
@ -431,9 +417,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 val;
|
||||
ssize_t ret;
|
||||
|
||||
@ -490,9 +474,7 @@ static DEVICE_ATTR(gt_RPn_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
|
||||
/* For now we have a static number of RP states */
|
||||
static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
u32 val;
|
||||
|
||||
if (attr == &dev_attr_gt_RP0_freq_mhz)
|
||||
@ -538,8 +520,8 @@ static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
|
||||
{
|
||||
|
||||
struct device *kdev = kobj_to_dev(kobj);
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct i915_error_state_file_priv error_priv;
|
||||
struct drm_i915_error_state_buf error_str;
|
||||
ssize_t ret_count = 0;
|
||||
@ -573,18 +555,10 @@ static ssize_t error_state_write(struct file *file, struct kobject *kobj,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
struct device *kdev = kobj_to_dev(kobj);
|
||||
struct drm_minor *minor = dev_to_drm_minor(kdev);
|
||||
struct drm_device *dev = minor->dev;
|
||||
int ret;
|
||||
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
|
||||
|
||||
DRM_DEBUG_DRIVER("Resetting error state\n");
|
||||
|
||||
ret = mutex_lock_interruptible(&dev->struct_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i915_destroy_error_state(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
i915_destroy_error_state(&dev_priv->drm);
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -597,37 +571,38 @@ static struct bin_attribute error_state_attr = {
|
||||
.write = error_state_write,
|
||||
};
|
||||
|
||||
void i915_setup_sysfs(struct drm_device *dev)
|
||||
void i915_setup_sysfs(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct device *kdev = dev_priv->drm.primary->kdev;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (HAS_RC6(dev)) {
|
||||
ret = sysfs_merge_group(&dev->primary->kdev->kobj,
|
||||
if (HAS_RC6(dev_priv)) {
|
||||
ret = sysfs_merge_group(&kdev->kobj,
|
||||
&rc6_attr_group);
|
||||
if (ret)
|
||||
DRM_ERROR("RC6 residency sysfs setup failed\n");
|
||||
}
|
||||
if (HAS_RC6p(dev)) {
|
||||
ret = sysfs_merge_group(&dev->primary->kdev->kobj,
|
||||
if (HAS_RC6p(dev_priv)) {
|
||||
ret = sysfs_merge_group(&kdev->kobj,
|
||||
&rc6p_attr_group);
|
||||
if (ret)
|
||||
DRM_ERROR("RC6p residency sysfs setup failed\n");
|
||||
}
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
|
||||
ret = sysfs_merge_group(&dev->primary->kdev->kobj,
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
|
||||
ret = sysfs_merge_group(&kdev->kobj,
|
||||
&media_rc6_attr_group);
|
||||
if (ret)
|
||||
DRM_ERROR("Media RC6 residency sysfs setup failed\n");
|
||||
}
|
||||
#endif
|
||||
if (HAS_L3_DPF(dev)) {
|
||||
ret = device_create_bin_file(dev->primary->kdev, &dpf_attrs);
|
||||
if (HAS_L3_DPF(dev_priv)) {
|
||||
ret = device_create_bin_file(kdev, &dpf_attrs);
|
||||
if (ret)
|
||||
DRM_ERROR("l3 parity sysfs setup failed\n");
|
||||
|
||||
if (NUM_L3_SLICES(dev) > 1) {
|
||||
ret = device_create_bin_file(dev->primary->kdev,
|
||||
if (NUM_L3_SLICES(dev_priv) > 1) {
|
||||
ret = device_create_bin_file(kdev,
|
||||
&dpf_attrs_1);
|
||||
if (ret)
|
||||
DRM_ERROR("l3 parity slice 1 setup failed\n");
|
||||
@ -635,30 +610,32 @@ void i915_setup_sysfs(struct drm_device *dev)
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
ret = sysfs_create_files(&dev->primary->kdev->kobj, vlv_attrs);
|
||||
else if (INTEL_INFO(dev)->gen >= 6)
|
||||
ret = sysfs_create_files(&dev->primary->kdev->kobj, gen6_attrs);
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
ret = sysfs_create_files(&kdev->kobj, vlv_attrs);
|
||||
else if (INTEL_GEN(dev_priv) >= 6)
|
||||
ret = sysfs_create_files(&kdev->kobj, gen6_attrs);
|
||||
if (ret)
|
||||
DRM_ERROR("RPS sysfs setup failed\n");
|
||||
|
||||
ret = sysfs_create_bin_file(&dev->primary->kdev->kobj,
|
||||
ret = sysfs_create_bin_file(&kdev->kobj,
|
||||
&error_state_attr);
|
||||
if (ret)
|
||||
DRM_ERROR("error_state sysfs setup failed\n");
|
||||
}
|
||||
|
||||
void i915_teardown_sysfs(struct drm_device *dev)
|
||||
void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
sysfs_remove_bin_file(&dev->primary->kdev->kobj, &error_state_attr);
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
sysfs_remove_files(&dev->primary->kdev->kobj, vlv_attrs);
|
||||
struct device *kdev = dev_priv->drm.primary->kdev;
|
||||
|
||||
sysfs_remove_bin_file(&kdev->kobj, &error_state_attr);
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
sysfs_remove_files(&kdev->kobj, vlv_attrs);
|
||||
else
|
||||
sysfs_remove_files(&dev->primary->kdev->kobj, gen6_attrs);
|
||||
device_remove_bin_file(dev->primary->kdev, &dpf_attrs_1);
|
||||
device_remove_bin_file(dev->primary->kdev, &dpf_attrs);
|
||||
sysfs_remove_files(&kdev->kobj, gen6_attrs);
|
||||
device_remove_bin_file(kdev, &dpf_attrs_1);
|
||||
device_remove_bin_file(kdev, &dpf_attrs);
|
||||
#ifdef CONFIG_PM
|
||||
sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group);
|
||||
sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6p_attr_group);
|
||||
sysfs_unmerge_group(&kdev->kobj, &rc6_attr_group);
|
||||
sysfs_unmerge_group(&kdev->kobj, &rc6p_attr_group);
|
||||
#endif
|
||||
}
|
||||
|
@ -65,9 +65,6 @@ void i915_check_vgpu(struct drm_i915_private *dev_priv)
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE);
|
||||
|
||||
if (!IS_HASWELL(dev_priv))
|
||||
return;
|
||||
|
||||
magic = __raw_i915_read64(dev_priv, vgtif_reg(magic));
|
||||
if (magic != VGT_MAGIC)
|
||||
return;
|
||||
|
@ -359,9 +359,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
enc_to_dig_port(&encoder->base);
|
||||
enum port port = intel_dig_port->port;
|
||||
enum port port = enc_to_dig_port(&encoder->base)->port;
|
||||
enum pipe pipe = intel_crtc->pipe;
|
||||
uint32_t tmp, eldv;
|
||||
i915_reg_t aud_config, aud_cntrl_st2;
|
||||
@ -407,13 +405,10 @@ static void ilk_audio_codec_enable(struct drm_connector *connector,
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->dev);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct intel_digital_port *intel_dig_port =
|
||||
enc_to_dig_port(&encoder->base);
|
||||
enum port port = intel_dig_port->port;
|
||||
enum port port = enc_to_dig_port(&encoder->base)->port;
|
||||
enum pipe pipe = intel_crtc->pipe;
|
||||
uint8_t *eld = connector->eld;
|
||||
uint32_t eldv;
|
||||
uint32_t tmp;
|
||||
uint32_t tmp, eldv;
|
||||
int len, i;
|
||||
i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2;
|
||||
|
||||
@ -581,26 +576,26 @@ void intel_init_audio_hooks(struct drm_i915_private *dev_priv)
|
||||
}
|
||||
}
|
||||
|
||||
static void i915_audio_component_get_power(struct device *dev)
|
||||
static void i915_audio_component_get_power(struct device *kdev)
|
||||
{
|
||||
intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
|
||||
intel_display_power_get(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
|
||||
}
|
||||
|
||||
static void i915_audio_component_put_power(struct device *dev)
|
||||
static void i915_audio_component_put_power(struct device *kdev)
|
||||
{
|
||||
intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
|
||||
intel_display_power_put(kdev_to_i915(kdev), POWER_DOMAIN_AUDIO);
|
||||
}
|
||||
|
||||
static void i915_audio_component_codec_wake_override(struct device *dev,
|
||||
static void i915_audio_component_codec_wake_override(struct device *kdev,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
|
||||
u32 tmp;
|
||||
|
||||
if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv))
|
||||
return;
|
||||
|
||||
i915_audio_component_get_power(dev);
|
||||
i915_audio_component_get_power(kdev);
|
||||
|
||||
/*
|
||||
* Enable/disable generating the codec wake signal, overriding the
|
||||
@ -618,13 +613,13 @@ static void i915_audio_component_codec_wake_override(struct device *dev,
|
||||
usleep_range(1000, 1500);
|
||||
}
|
||||
|
||||
i915_audio_component_put_power(dev);
|
||||
i915_audio_component_put_power(kdev);
|
||||
}
|
||||
|
||||
/* Get CDCLK in kHz */
|
||||
static int i915_audio_component_get_cdclk_freq(struct device *dev)
|
||||
static int i915_audio_component_get_cdclk_freq(struct device *kdev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
|
||||
|
||||
if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
|
||||
return -ENODEV;
|
||||
@ -632,10 +627,10 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
|
||||
return dev_priv->cdclk_freq;
|
||||
}
|
||||
|
||||
static int i915_audio_component_sync_audio_rate(struct device *dev,
|
||||
static int i915_audio_component_sync_audio_rate(struct device *kdev,
|
||||
int port, int rate)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_crtc *crtc;
|
||||
struct drm_display_mode *mode;
|
||||
@ -652,7 +647,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
|
||||
!IS_HASWELL(dev_priv))
|
||||
return 0;
|
||||
|
||||
i915_audio_component_get_power(dev);
|
||||
i915_audio_component_get_power(kdev);
|
||||
mutex_lock(&dev_priv->av_mutex);
|
||||
/* 1. get the pipe */
|
||||
intel_encoder = dev_priv->dig_port_map[port];
|
||||
@ -703,15 +698,15 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev_priv->av_mutex);
|
||||
i915_audio_component_put_power(dev);
|
||||
i915_audio_component_put_power(kdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int i915_audio_component_get_eld(struct device *dev, int port,
|
||||
static int i915_audio_component_get_eld(struct device *kdev, int port,
|
||||
bool *enabled,
|
||||
unsigned char *buf, int max_bytes)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(kdev);
|
||||
struct intel_encoder *intel_encoder;
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
const u8 *eld;
|
||||
@ -745,11 +740,11 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
|
||||
.get_eld = i915_audio_component_get_eld,
|
||||
};
|
||||
|
||||
static int i915_audio_component_bind(struct device *i915_dev,
|
||||
struct device *hda_dev, void *data)
|
||||
static int i915_audio_component_bind(struct device *i915_kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct i915_audio_component *acomp = data;
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
|
||||
int i;
|
||||
|
||||
if (WARN_ON(acomp->ops || acomp->dev))
|
||||
@ -757,7 +752,7 @@ static int i915_audio_component_bind(struct device *i915_dev,
|
||||
|
||||
drm_modeset_lock_all(&dev_priv->drm);
|
||||
acomp->ops = &i915_audio_component_ops;
|
||||
acomp->dev = i915_dev;
|
||||
acomp->dev = i915_kdev;
|
||||
BUILD_BUG_ON(MAX_PORTS != I915_MAX_PORTS);
|
||||
for (i = 0; i < ARRAY_SIZE(acomp->aud_sample_rate); i++)
|
||||
acomp->aud_sample_rate[i] = 0;
|
||||
@ -767,11 +762,11 @@ static int i915_audio_component_bind(struct device *i915_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i915_audio_component_unbind(struct device *i915_dev,
|
||||
struct device *hda_dev, void *data)
|
||||
static void i915_audio_component_unbind(struct device *i915_kdev,
|
||||
struct device *hda_kdev, void *data)
|
||||
{
|
||||
struct i915_audio_component *acomp = data;
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(i915_dev);
|
||||
struct drm_i915_private *dev_priv = kdev_to_i915(i915_kdev);
|
||||
|
||||
drm_modeset_lock_all(&dev_priv->drm);
|
||||
acomp->ops = NULL;
|
||||
|
@ -462,7 +462,10 @@ static int intel_breadcrumbs_signaler(void *arg)
|
||||
*/
|
||||
intel_engine_remove_wait(engine,
|
||||
&request->signaling.wait);
|
||||
|
||||
local_bh_disable();
|
||||
fence_signal(&request->fence);
|
||||
local_bh_enable(); /* kick start the tasklets */
|
||||
|
||||
/* Find the next oldest signal. Note that as we have
|
||||
* not been holding the lock, another client may
|
||||
|
@ -100,13 +100,14 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int i, pipe = intel_crtc->pipe;
|
||||
uint16_t coeffs[9] = { 0, };
|
||||
struct intel_crtc_state *intel_crtc_state = to_intel_crtc_state(crtc_state);
|
||||
|
||||
if (crtc_state->ctm) {
|
||||
struct drm_color_ctm *ctm =
|
||||
(struct drm_color_ctm *)crtc_state->ctm->data;
|
||||
uint64_t input[9] = { 0, };
|
||||
|
||||
if (intel_crtc->config->limited_color_range) {
|
||||
if (intel_crtc_state->limited_color_range) {
|
||||
ctm_mult_by_limited(input, ctm->matrix);
|
||||
} else {
|
||||
for (i = 0; i < ARRAY_SIZE(input); i++)
|
||||
@ -158,7 +159,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
* into consideration.
|
||||
*/
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (intel_crtc->config->limited_color_range)
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
coeffs[i * 3 + i] =
|
||||
I9XX_CSC_COEFF_LIMITED_RANGE;
|
||||
else
|
||||
@ -182,7 +183,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
if (INTEL_INFO(dev)->gen > 6) {
|
||||
uint16_t postoff = 0;
|
||||
|
||||
if (intel_crtc->config->limited_color_range)
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
postoff = (16 * (1 << 12) / 255) & 0x1fff;
|
||||
|
||||
I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
|
||||
@ -193,7 +194,7 @@ static void i9xx_load_csc_matrix(struct drm_crtc_state *crtc_state)
|
||||
} else {
|
||||
uint32_t mode = CSC_MODE_YUV_TO_RGB;
|
||||
|
||||
if (intel_crtc->config->limited_color_range)
|
||||
if (intel_crtc_state->limited_color_range)
|
||||
mode |= CSC_BLACK_SCREEN_OFFSET;
|
||||
|
||||
I915_WRITE(PIPE_CSC_MODE(pipe), mode);
|
||||
@ -263,7 +264,8 @@ void intel_color_set_csc(struct drm_crtc_state *crtc_state)
|
||||
|
||||
/* Loads the legacy palette/gamma unit for the CRTC. */
|
||||
static void i9xx_load_luts_internal(struct drm_crtc *crtc,
|
||||
struct drm_property_blob *blob)
|
||||
struct drm_property_blob *blob,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -272,7 +274,7 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
|
||||
int i;
|
||||
|
||||
if (HAS_GMCH_DISPLAY(dev)) {
|
||||
if (intel_crtc_has_type(intel_crtc->config, INTEL_OUTPUT_DSI))
|
||||
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI))
|
||||
assert_dsi_pll_enabled(dev_priv);
|
||||
else
|
||||
assert_pll_enabled(dev_priv, pipe);
|
||||
@ -305,7 +307,8 @@ static void i9xx_load_luts_internal(struct drm_crtc *crtc,
|
||||
|
||||
static void i9xx_load_luts(struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
i9xx_load_luts_internal(crtc_state->crtc, crtc_state->gamma_lut);
|
||||
i9xx_load_luts_internal(crtc_state->crtc, crtc_state->gamma_lut,
|
||||
to_intel_crtc_state(crtc_state));
|
||||
}
|
||||
|
||||
/* Loads the legacy palette/gamma unit for the CRTC on Haswell. */
|
||||
@ -323,7 +326,7 @@ static void haswell_load_luts(struct drm_crtc_state *crtc_state)
|
||||
* Workaround : Do not read or write the pipe palette/gamma data while
|
||||
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
|
||||
*/
|
||||
if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
|
||||
if (IS_HASWELL(dev) && intel_crtc_state->ips_enabled &&
|
||||
(intel_crtc_state->gamma_mode == GAMMA_MODE_MODE_SPLIT)) {
|
||||
hsw_disable_ips(intel_crtc);
|
||||
reenable_ips = true;
|
||||
@ -436,7 +439,8 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
|
||||
/* Turn off degamma/gamma on CGM block. */
|
||||
I915_WRITE(CGM_PIPE_MODE(pipe),
|
||||
(state->ctm ? CGM_PIPE_MODE_CSC : 0));
|
||||
i9xx_load_luts_internal(crtc, state->gamma_lut);
|
||||
i9xx_load_luts_internal(crtc, state->gamma_lut,
|
||||
to_intel_crtc_state(state));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -479,7 +483,7 @@ static void cherryview_load_luts(struct drm_crtc_state *state)
|
||||
* Also program a linear LUT in the legacy block (behind the
|
||||
* CGM block).
|
||||
*/
|
||||
i9xx_load_luts_internal(crtc, NULL);
|
||||
i9xx_load_luts_internal(crtc, NULL, to_intel_crtc_state(state));
|
||||
}
|
||||
|
||||
void intel_color_load_luts(struct drm_crtc_state *crtc_state)
|
||||
|
@ -143,13 +143,15 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
|
||||
|
||||
/* Note: The caller is required to filter out dpms modes not supported by the
|
||||
* platform. */
|
||||
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
|
||||
static void intel_crt_set_dpms(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crt *crt = intel_encoder_to_crt(encoder);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
|
||||
u32 adpa;
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 5)
|
||||
@ -193,23 +195,45 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
|
||||
I915_WRITE(crt->adpa_reg, adpa);
|
||||
}
|
||||
|
||||
static void intel_disable_crt(struct intel_encoder *encoder)
|
||||
static void intel_disable_crt(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
intel_crt_set_dpms(encoder, old_crtc_state, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void pch_disable_crt(struct intel_encoder *encoder)
|
||||
static void pch_disable_crt(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
}
|
||||
|
||||
static void pch_post_disable_crt(struct intel_encoder *encoder)
|
||||
static void pch_post_disable_crt(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_disable_crt(encoder);
|
||||
intel_disable_crt(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static void intel_enable_crt(struct intel_encoder *encoder)
|
||||
static void hsw_post_disable_crt(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_crt_set_dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
||||
pch_post_disable_crt(encoder, old_crtc_state, old_conn_state);
|
||||
|
||||
lpt_disable_pch_transcoder(dev_priv);
|
||||
lpt_disable_iclkip(dev_priv);
|
||||
|
||||
intel_ddi_fdi_post_disable(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static void intel_enable_crt(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
intel_crt_set_dpms(encoder, pipe_config, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
@ -253,7 +277,8 @@ intel_crt_mode_valid(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static bool intel_crt_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
|
||||
@ -894,6 +919,7 @@ void intel_crt_init(struct drm_device *dev)
|
||||
if (HAS_DDI(dev)) {
|
||||
crt->base.get_config = hsw_crt_get_config;
|
||||
crt->base.get_hw_state = intel_ddi_get_hw_state;
|
||||
crt->base.post_disable = hsw_post_disable_crt;
|
||||
} else {
|
||||
crt->base.get_config = intel_crt_get_config;
|
||||
crt->base.get_hw_state = intel_crt_get_hw_state;
|
||||
|
@ -34,15 +34,15 @@
|
||||
* low-power state and comes back to normal.
|
||||
*/
|
||||
|
||||
#define I915_CSR_KBL "i915/kbl_dmc_ver1.bin"
|
||||
#define I915_CSR_KBL "i915/kbl_dmc_ver1_01.bin"
|
||||
MODULE_FIRMWARE(I915_CSR_KBL);
|
||||
#define KBL_CSR_VERSION_REQUIRED CSR_VERSION(1, 1)
|
||||
|
||||
#define I915_CSR_SKL "i915/skl_dmc_ver1.bin"
|
||||
#define I915_CSR_SKL "i915/skl_dmc_ver1_26.bin"
|
||||
MODULE_FIRMWARE(I915_CSR_SKL);
|
||||
#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23)
|
||||
#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 26)
|
||||
|
||||
#define I915_CSR_BXT "i915/bxt_dmc_ver1.bin"
|
||||
#define I915_CSR_BXT "i915/bxt_dmc_ver1_07.bin"
|
||||
MODULE_FIRMWARE(I915_CSR_BXT);
|
||||
#define BXT_CSR_VERSION_REQUIRED CSR_VERSION(1, 7)
|
||||
|
||||
|
@ -546,6 +546,27 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
|
||||
DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
|
||||
}
|
||||
|
||||
static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
|
||||
{
|
||||
switch (pll->id) {
|
||||
case DPLL_ID_WRPLL1:
|
||||
return PORT_CLK_SEL_WRPLL1;
|
||||
case DPLL_ID_WRPLL2:
|
||||
return PORT_CLK_SEL_WRPLL2;
|
||||
case DPLL_ID_SPLL:
|
||||
return PORT_CLK_SEL_SPLL;
|
||||
case DPLL_ID_LCPLL_810:
|
||||
return PORT_CLK_SEL_LCPLL_810;
|
||||
case DPLL_ID_LCPLL_1350:
|
||||
return PORT_CLK_SEL_LCPLL_1350;
|
||||
case DPLL_ID_LCPLL_2700:
|
||||
return PORT_CLK_SEL_LCPLL_2700;
|
||||
default:
|
||||
MISSING_CASE(pll->id);
|
||||
return PORT_CLK_SEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Starting with Haswell, different DDI ports can work in FDI mode for
|
||||
* connection to the PCH-located connectors. For this, it is necessary to train
|
||||
* both the DDI port and PCH receiver for the desired DDI buffer settings.
|
||||
@ -561,7 +582,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_encoder *encoder;
|
||||
u32 temp, i, rx_ctl_val;
|
||||
u32 temp, i, rx_ctl_val, ddi_pll_sel;
|
||||
|
||||
for_each_encoder_on_crtc(dev, crtc, encoder) {
|
||||
WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
|
||||
@ -592,8 +613,9 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
|
||||
|
||||
/* Configure Port Clock Select */
|
||||
I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
|
||||
WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL);
|
||||
ddi_pll_sel = hsw_pll_to_ddi_pll_sel(intel_crtc->config->shared_dpll);
|
||||
I915_WRITE(PORT_CLK_SEL(PORT_E), ddi_pll_sel);
|
||||
WARN_ON(ddi_pll_sel != PORT_CLK_SEL_SPLL);
|
||||
|
||||
/* Start the training iterating through available voltages and emphasis,
|
||||
* testing each value twice. */
|
||||
@ -870,7 +892,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
|
||||
int link_clock = 0;
|
||||
uint32_t dpll_ctl1, dpll;
|
||||
|
||||
dpll = pipe_config->ddi_pll_sel;
|
||||
dpll = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll);
|
||||
|
||||
dpll_ctl1 = I915_READ(DPLL_CTRL1);
|
||||
|
||||
@ -918,7 +940,7 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
|
||||
int link_clock = 0;
|
||||
u32 val, pll;
|
||||
|
||||
val = pipe_config->ddi_pll_sel;
|
||||
val = hsw_pll_to_ddi_pll_sel(pipe_config->shared_dpll);
|
||||
switch (val & PORT_CLK_SEL_MASK) {
|
||||
case PORT_CLK_SEL_LCPLL_810:
|
||||
link_clock = 81000;
|
||||
@ -1586,13 +1608,15 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
|
||||
}
|
||||
|
||||
void intel_ddi_clk_select(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *pipe_config)
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum port port = intel_ddi_get_encoder_port(encoder);
|
||||
|
||||
if (WARN_ON(!pll))
|
||||
return;
|
||||
|
||||
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
|
||||
uint32_t dpll = pipe_config->ddi_pll_sel;
|
||||
uint32_t val;
|
||||
|
||||
/* DDI -> PLL mapping */
|
||||
@ -1600,70 +1624,91 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
|
||||
|
||||
val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
|
||||
DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
|
||||
val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) |
|
||||
val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->id, port) |
|
||||
DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
|
||||
|
||||
I915_WRITE(DPLL_CTRL2, val);
|
||||
|
||||
} else if (INTEL_INFO(dev_priv)->gen < 9) {
|
||||
WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
|
||||
I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
|
||||
I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
|
||||
static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
|
||||
int link_rate, uint32_t lane_count,
|
||||
struct intel_shared_dpll *pll,
|
||||
bool link_mst)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum port port = intel_ddi_get_encoder_port(encoder);
|
||||
|
||||
intel_dp_set_link_params(intel_dp, link_rate, lane_count,
|
||||
link_mst);
|
||||
if (encoder->type == INTEL_OUTPUT_EDP)
|
||||
intel_edp_panel_on(intel_dp);
|
||||
|
||||
intel_ddi_clk_select(encoder, pll);
|
||||
intel_prepare_dp_ddi_buffers(encoder);
|
||||
intel_ddi_init_dp_buf_reg(encoder);
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
|
||||
intel_dp_stop_link_train(intel_dp);
|
||||
}
|
||||
|
||||
static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
|
||||
bool has_hdmi_sink,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
struct intel_shared_dpll *pll)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct drm_encoder *drm_encoder = &encoder->base;
|
||||
enum port port = intel_ddi_get_encoder_port(encoder);
|
||||
int level = intel_ddi_hdmi_level(dev_priv, port);
|
||||
|
||||
intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
|
||||
intel_ddi_clk_select(encoder, pll);
|
||||
intel_prepare_hdmi_ddi_buffers(encoder);
|
||||
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
|
||||
skl_ddi_set_iboost(encoder, level);
|
||||
else if (IS_BROXTON(dev_priv))
|
||||
bxt_ddi_vswing_sequence(dev_priv, level, port,
|
||||
INTEL_OUTPUT_HDMI);
|
||||
|
||||
intel_hdmi->set_infoframes(drm_encoder,
|
||||
has_hdmi_sink,
|
||||
adjusted_mode);
|
||||
}
|
||||
|
||||
static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
|
||||
enum port port = intel_ddi_get_encoder_port(intel_encoder);
|
||||
int type = intel_encoder->type;
|
||||
|
||||
if (type == INTEL_OUTPUT_HDMI) {
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
|
||||
intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
|
||||
}
|
||||
|
||||
if (type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
intel_edp_panel_on(intel_dp);
|
||||
}
|
||||
|
||||
intel_ddi_clk_select(intel_encoder, crtc->config);
|
||||
|
||||
if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
intel_prepare_dp_ddi_buffers(intel_encoder);
|
||||
|
||||
intel_dp_set_link_params(intel_dp, crtc->config);
|
||||
|
||||
intel_ddi_init_dp_buf_reg(intel_encoder);
|
||||
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
|
||||
intel_dp_stop_link_train(intel_dp);
|
||||
} else if (type == INTEL_OUTPUT_HDMI) {
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
|
||||
int level = intel_ddi_hdmi_level(dev_priv, port);
|
||||
|
||||
intel_prepare_hdmi_ddi_buffers(intel_encoder);
|
||||
|
||||
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
|
||||
skl_ddi_set_iboost(intel_encoder, level);
|
||||
else if (IS_BROXTON(dev_priv))
|
||||
bxt_ddi_vswing_sequence(dev_priv, level, port,
|
||||
INTEL_OUTPUT_HDMI);
|
||||
|
||||
intel_hdmi->set_infoframes(encoder,
|
||||
crtc->config->has_hdmi_sink,
|
||||
&crtc->config->base.adjusted_mode);
|
||||
intel_ddi_pre_enable_dp(intel_encoder,
|
||||
crtc->config->port_clock,
|
||||
crtc->config->lane_count,
|
||||
crtc->config->shared_dpll,
|
||||
intel_crtc_has_type(crtc->config,
|
||||
INTEL_OUTPUT_DP_MST));
|
||||
}
|
||||
if (type == INTEL_OUTPUT_HDMI) {
|
||||
intel_ddi_pre_enable_hdmi(intel_encoder,
|
||||
crtc->config->has_hdmi_sink,
|
||||
&crtc->config->base.adjusted_mode,
|
||||
crtc->config->shared_dpll);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
||||
static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
@ -1673,6 +1718,8 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
||||
uint32_t val;
|
||||
bool wait = false;
|
||||
|
||||
/* old_crtc_state and old_conn_state are NULL when called from DP_MST */
|
||||
|
||||
val = I915_READ(DDI_BUF_CTL(port));
|
||||
if (val & DDI_BUF_CTL_ENABLE) {
|
||||
val &= ~DDI_BUF_CTL_ENABLE;
|
||||
@ -1708,7 +1755,42 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_enable_ddi(struct intel_encoder *intel_encoder)
|
||||
void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
|
||||
* and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
|
||||
* step 13 is the correct place for it. Step 18 is where it was
|
||||
* originally before the BUN.
|
||||
*/
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_RX_ENABLE;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
|
||||
intel_ddi_post_disable(intel_encoder, old_crtc_state, old_conn_state);
|
||||
|
||||
val = I915_READ(FDI_RX_MISC(PIPE_A));
|
||||
val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
|
||||
val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
|
||||
I915_WRITE(FDI_RX_MISC(PIPE_A), val);
|
||||
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_PCDCLK;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_RX_PLL_ENABLE;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
}
|
||||
|
||||
static void intel_enable_ddi(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
@ -1737,7 +1819,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
|
||||
|
||||
intel_edp_backlight_on(intel_dp);
|
||||
intel_psr_enable(intel_dp);
|
||||
intel_edp_drrs_enable(intel_dp);
|
||||
intel_edp_drrs_enable(intel_dp, pipe_config);
|
||||
}
|
||||
|
||||
if (intel_crtc->config->has_audio) {
|
||||
@ -1746,7 +1828,9 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_disable_ddi(struct intel_encoder *intel_encoder)
|
||||
static void intel_disable_ddi(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
@ -1763,7 +1847,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
|
||||
if (type == INTEL_OUTPUT_EDP) {
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
|
||||
|
||||
intel_edp_drrs_disable(intel_dp);
|
||||
intel_edp_drrs_disable(intel_dp, old_crtc_state);
|
||||
intel_psr_disable(intel_dp);
|
||||
intel_edp_backlight_off(intel_dp);
|
||||
}
|
||||
@ -2052,7 +2136,9 @@ bxt_ddi_phy_calc_lane_lat_optim_mask(struct intel_encoder *encoder,
|
||||
}
|
||||
}
|
||||
|
||||
static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder)
|
||||
static void bxt_ddi_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dport->base.base.dev);
|
||||
@ -2141,38 +2227,6 @@ void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp)
|
||||
udelay(600);
|
||||
}
|
||||
|
||||
void intel_ddi_fdi_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->dev);
|
||||
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* Bspec lists this as both step 13 (before DDI_BUF_CTL disable)
|
||||
* and step 18 (after clearing PORT_CLK_SEL). Based on a BUN,
|
||||
* step 13 is the correct place for it. Step 18 is where it was
|
||||
* originally before the BUN.
|
||||
*/
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_RX_ENABLE;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
|
||||
intel_ddi_post_disable(intel_encoder);
|
||||
|
||||
val = I915_READ(FDI_RX_MISC(PIPE_A));
|
||||
val &= ~(FDI_RX_PWRDN_LANE1_MASK | FDI_RX_PWRDN_LANE0_MASK);
|
||||
val |= FDI_RX_PWRDN_LANE1_VAL(2) | FDI_RX_PWRDN_LANE0_VAL(2);
|
||||
I915_WRITE(FDI_RX_MISC(PIPE_A), val);
|
||||
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_PCDCLK;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
|
||||
val = I915_READ(FDI_RX_CTL(PIPE_A));
|
||||
val &= ~FDI_RX_PLL_ENABLE;
|
||||
I915_WRITE(FDI_RX_CTL(PIPE_A), val);
|
||||
}
|
||||
|
||||
void intel_ddi_get_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
@ -2272,7 +2326,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
|
||||
}
|
||||
|
||||
static bool intel_ddi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
int type = encoder->type;
|
||||
@ -2285,9 +2340,9 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
|
||||
pipe_config->cpu_transcoder = TRANSCODER_EDP;
|
||||
|
||||
if (type == INTEL_OUTPUT_HDMI)
|
||||
ret = intel_hdmi_compute_config(encoder, pipe_config);
|
||||
ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state);
|
||||
else
|
||||
ret = intel_dp_compute_config(encoder, pipe_config);
|
||||
ret = intel_dp_compute_config(encoder, pipe_config, conn_state);
|
||||
|
||||
if (IS_BROXTON(dev_priv) && ret)
|
||||
pipe_config->lane_lat_optim_mask =
|
||||
@ -2338,6 +2393,45 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
|
||||
return connector;
|
||||
}
|
||||
|
||||
struct intel_shared_dpll *
|
||||
intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
|
||||
{
|
||||
struct intel_connector *connector = intel_dp->attached_connector;
|
||||
struct intel_encoder *encoder = connector->encoder;
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_shared_dpll *pll = NULL;
|
||||
struct intel_shared_dpll_config tmp_pll_config;
|
||||
enum intel_dpll_id dpll_id;
|
||||
|
||||
if (IS_BROXTON(dev_priv)) {
|
||||
dpll_id = (enum intel_dpll_id)dig_port->port;
|
||||
/*
|
||||
* Select the required PLL. This works for platforms where
|
||||
* there is no shared DPLL.
|
||||
*/
|
||||
pll = &dev_priv->shared_dplls[dpll_id];
|
||||
if (WARN_ON(pll->active_mask)) {
|
||||
|
||||
DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
|
||||
pll->active_mask);
|
||||
return NULL;
|
||||
}
|
||||
tmp_pll_config = pll->config;
|
||||
if (!bxt_ddi_dp_set_dpll_hw_state(clock,
|
||||
&pll->config.hw_state)) {
|
||||
DRM_ERROR("Could not setup DPLL\n");
|
||||
pll->config = tmp_pll_config;
|
||||
return NULL;
|
||||
}
|
||||
} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
|
||||
pll = skl_find_link_pll(dev_priv, clock);
|
||||
} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
|
||||
pll = hsw_ddi_dp_get_dpll(encoder, clock);
|
||||
}
|
||||
return pll;
|
||||
}
|
||||
|
||||
void intel_ddi_init(struct drm_device *dev, enum port port)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
@ -46,71 +46,70 @@ void intel_device_info_dump(struct drm_i915_private *dev_priv)
|
||||
|
||||
static void cherryview_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_device_info *info = mkwrite_device_info(dev_priv);
|
||||
struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
|
||||
u32 fuse, eu_dis;
|
||||
|
||||
fuse = I915_READ(CHV_FUSE_GT);
|
||||
|
||||
info->slice_total = 1;
|
||||
sseu->slice_mask = BIT(0);
|
||||
|
||||
if (!(fuse & CHV_FGT_DISABLE_SS0)) {
|
||||
info->subslice_per_slice++;
|
||||
sseu->subslice_mask |= BIT(0);
|
||||
eu_dis = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
|
||||
CHV_FGT_EU_DIS_SS0_R1_MASK);
|
||||
info->eu_total += 8 - hweight32(eu_dis);
|
||||
sseu->eu_total += 8 - hweight32(eu_dis);
|
||||
}
|
||||
|
||||
if (!(fuse & CHV_FGT_DISABLE_SS1)) {
|
||||
info->subslice_per_slice++;
|
||||
sseu->subslice_mask |= BIT(1);
|
||||
eu_dis = fuse & (CHV_FGT_EU_DIS_SS1_R0_MASK |
|
||||
CHV_FGT_EU_DIS_SS1_R1_MASK);
|
||||
info->eu_total += 8 - hweight32(eu_dis);
|
||||
sseu->eu_total += 8 - hweight32(eu_dis);
|
||||
}
|
||||
|
||||
info->subslice_total = info->subslice_per_slice;
|
||||
/*
|
||||
* CHV expected to always have a uniform distribution of EU
|
||||
* across subslices.
|
||||
*/
|
||||
info->eu_per_subslice = info->subslice_total ?
|
||||
info->eu_total / info->subslice_total :
|
||||
sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
|
||||
sseu->eu_total / sseu_subslice_total(sseu) :
|
||||
0;
|
||||
/*
|
||||
* CHV supports subslice power gating on devices with more than
|
||||
* one subslice, and supports EU power gating on devices with
|
||||
* more than one EU pair per subslice.
|
||||
*/
|
||||
info->has_slice_pg = 0;
|
||||
info->has_subslice_pg = (info->subslice_total > 1);
|
||||
info->has_eu_pg = (info->eu_per_subslice > 2);
|
||||
sseu->has_slice_pg = 0;
|
||||
sseu->has_subslice_pg = sseu_subslice_total(sseu) > 1;
|
||||
sseu->has_eu_pg = (sseu->eu_per_subslice > 2);
|
||||
}
|
||||
|
||||
static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_device_info *info = mkwrite_device_info(dev_priv);
|
||||
struct sseu_dev_info *sseu = &info->sseu;
|
||||
int s_max = 3, ss_max = 4, eu_max = 8;
|
||||
int s, ss;
|
||||
u32 fuse2, s_enable, ss_disable, eu_disable;
|
||||
u32 fuse2, eu_disable;
|
||||
u8 eu_mask = 0xff;
|
||||
|
||||
fuse2 = I915_READ(GEN8_FUSE2);
|
||||
s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
ss_disable = (fuse2 & GEN9_F2_SS_DIS_MASK) >> GEN9_F2_SS_DIS_SHIFT;
|
||||
sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
|
||||
info->slice_total = hweight32(s_enable);
|
||||
/*
|
||||
* The subslice disable field is global, i.e. it applies
|
||||
* to each of the enabled slices.
|
||||
*/
|
||||
info->subslice_per_slice = ss_max - hweight32(ss_disable);
|
||||
info->subslice_total = info->slice_total * info->subslice_per_slice;
|
||||
sseu->subslice_mask = (1 << ss_max) - 1;
|
||||
sseu->subslice_mask &= ~((fuse2 & GEN9_F2_SS_DIS_MASK) >>
|
||||
GEN9_F2_SS_DIS_SHIFT);
|
||||
|
||||
/*
|
||||
* Iterate through enabled slices and subslices to
|
||||
* count the total enabled EU.
|
||||
*/
|
||||
for (s = 0; s < s_max; s++) {
|
||||
if (!(s_enable & BIT(s)))
|
||||
if (!(sseu->slice_mask & BIT(s)))
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
||||
@ -118,7 +117,7 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
int eu_per_ss;
|
||||
|
||||
if (ss_disable & BIT(ss))
|
||||
if (!(sseu->subslice_mask & BIT(ss)))
|
||||
/* skip disabled subslice */
|
||||
continue;
|
||||
|
||||
@ -131,9 +130,9 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* subslices if they are unbalanced.
|
||||
*/
|
||||
if (eu_per_ss == 7)
|
||||
info->subslice_7eu[s] |= BIT(ss);
|
||||
sseu->subslice_7eu[s] |= BIT(ss);
|
||||
|
||||
info->eu_total += eu_per_ss;
|
||||
sseu->eu_total += eu_per_ss;
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,9 +143,9 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* recovery. BXT is expected to be perfectly uniform in EU
|
||||
* distribution.
|
||||
*/
|
||||
info->eu_per_subslice = info->subslice_total ?
|
||||
DIV_ROUND_UP(info->eu_total,
|
||||
info->subslice_total) : 0;
|
||||
sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
|
||||
DIV_ROUND_UP(sseu->eu_total,
|
||||
sseu_subslice_total(sseu)) : 0;
|
||||
/*
|
||||
* SKL supports slice power gating on devices with more than
|
||||
* one slice, and supports EU power gating on devices with
|
||||
@ -155,15 +154,15 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* supports EU power gating on devices with more than one EU
|
||||
* pair per subslice.
|
||||
*/
|
||||
info->has_slice_pg =
|
||||
sseu->has_slice_pg =
|
||||
(IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) &&
|
||||
info->slice_total > 1;
|
||||
info->has_subslice_pg =
|
||||
IS_BROXTON(dev_priv) && info->subslice_total > 1;
|
||||
info->has_eu_pg = info->eu_per_subslice > 2;
|
||||
hweight8(sseu->slice_mask) > 1;
|
||||
sseu->has_subslice_pg =
|
||||
IS_BROXTON(dev_priv) && sseu_subslice_total(sseu) > 1;
|
||||
sseu->has_eu_pg = sseu->eu_per_subslice > 2;
|
||||
|
||||
if (IS_BROXTON(dev_priv)) {
|
||||
#define IS_SS_DISABLED(_ss_disable, ss) (_ss_disable & BIT(ss))
|
||||
#define IS_SS_DISABLED(ss) (!(sseu->subslice_mask & BIT(ss)))
|
||||
/*
|
||||
* There is a HW issue in 2x6 fused down parts that requires
|
||||
* Pooled EU to be enabled as a WA. The pool configuration
|
||||
@ -171,19 +170,18 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* doesn't affect if the device has all 3 subslices enabled.
|
||||
*/
|
||||
/* WaEnablePooledEuFor2x6:bxt */
|
||||
info->has_pooled_eu = ((info->subslice_per_slice == 3) ||
|
||||
(info->subslice_per_slice == 2 &&
|
||||
info->has_pooled_eu = ((hweight8(sseu->subslice_mask) == 3) ||
|
||||
(hweight8(sseu->subslice_mask) == 2 &&
|
||||
INTEL_REVID(dev_priv) < BXT_REVID_C0));
|
||||
|
||||
info->min_eu_in_pool = 0;
|
||||
sseu->min_eu_in_pool = 0;
|
||||
if (info->has_pooled_eu) {
|
||||
if (IS_SS_DISABLED(ss_disable, 0) ||
|
||||
IS_SS_DISABLED(ss_disable, 2))
|
||||
info->min_eu_in_pool = 3;
|
||||
else if (IS_SS_DISABLED(ss_disable, 1))
|
||||
info->min_eu_in_pool = 6;
|
||||
if (IS_SS_DISABLED(2) || IS_SS_DISABLED(0))
|
||||
sseu->min_eu_in_pool = 3;
|
||||
else if (IS_SS_DISABLED(1))
|
||||
sseu->min_eu_in_pool = 6;
|
||||
else
|
||||
info->min_eu_in_pool = 9;
|
||||
sseu->min_eu_in_pool = 9;
|
||||
}
|
||||
#undef IS_SS_DISABLED
|
||||
}
|
||||
@ -191,14 +189,20 @@ static void gen9_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
|
||||
static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_device_info *info = mkwrite_device_info(dev_priv);
|
||||
struct sseu_dev_info *sseu = &mkwrite_device_info(dev_priv)->sseu;
|
||||
const int s_max = 3, ss_max = 3, eu_max = 8;
|
||||
int s, ss;
|
||||
u32 fuse2, eu_disable[s_max], s_enable, ss_disable;
|
||||
u32 fuse2, eu_disable[s_max];
|
||||
|
||||
fuse2 = I915_READ(GEN8_FUSE2);
|
||||
s_enable = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
ss_disable = (fuse2 & GEN8_F2_SS_DIS_MASK) >> GEN8_F2_SS_DIS_SHIFT;
|
||||
sseu->slice_mask = (fuse2 & GEN8_F2_S_ENA_MASK) >> GEN8_F2_S_ENA_SHIFT;
|
||||
/*
|
||||
* The subslice disable field is global, i.e. it applies
|
||||
* to each of the enabled slices.
|
||||
*/
|
||||
sseu->subslice_mask = BIT(ss_max) - 1;
|
||||
sseu->subslice_mask &= ~((fuse2 & GEN8_F2_SS_DIS_MASK) >>
|
||||
GEN8_F2_SS_DIS_SHIFT);
|
||||
|
||||
eu_disable[0] = I915_READ(GEN8_EU_DISABLE0) & GEN8_EU_DIS0_S0_MASK;
|
||||
eu_disable[1] = (I915_READ(GEN8_EU_DISABLE0) >> GEN8_EU_DIS0_S1_SHIFT) |
|
||||
@ -208,28 +212,19 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
((I915_READ(GEN8_EU_DISABLE2) & GEN8_EU_DIS2_S2_MASK) <<
|
||||
(32 - GEN8_EU_DIS1_S2_SHIFT));
|
||||
|
||||
info->slice_total = hweight32(s_enable);
|
||||
|
||||
/*
|
||||
* The subslice disable field is global, i.e. it applies
|
||||
* to each of the enabled slices.
|
||||
*/
|
||||
info->subslice_per_slice = ss_max - hweight32(ss_disable);
|
||||
info->subslice_total = info->slice_total * info->subslice_per_slice;
|
||||
|
||||
/*
|
||||
* Iterate through enabled slices and subslices to
|
||||
* count the total enabled EU.
|
||||
*/
|
||||
for (s = 0; s < s_max; s++) {
|
||||
if (!(s_enable & (0x1 << s)))
|
||||
if (!(sseu->slice_mask & BIT(s)))
|
||||
/* skip disabled slice */
|
||||
continue;
|
||||
|
||||
for (ss = 0; ss < ss_max; ss++) {
|
||||
u32 n_disabled;
|
||||
|
||||
if (ss_disable & (0x1 << ss))
|
||||
if (!(sseu->subslice_mask & BIT(ss)))
|
||||
/* skip disabled subslice */
|
||||
continue;
|
||||
|
||||
@ -239,9 +234,9 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* Record which subslices have 7 EUs.
|
||||
*/
|
||||
if (eu_max - n_disabled == 7)
|
||||
info->subslice_7eu[s] |= 1 << ss;
|
||||
sseu->subslice_7eu[s] |= 1 << ss;
|
||||
|
||||
info->eu_total += eu_max - n_disabled;
|
||||
sseu->eu_total += eu_max - n_disabled;
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,16 +245,17 @@ static void broadwell_sseu_info_init(struct drm_i915_private *dev_priv)
|
||||
* subslices with the exception that any one EU in any one subslice may
|
||||
* be fused off for die recovery.
|
||||
*/
|
||||
info->eu_per_subslice = info->subslice_total ?
|
||||
DIV_ROUND_UP(info->eu_total, info->subslice_total) : 0;
|
||||
sseu->eu_per_subslice = sseu_subslice_total(sseu) ?
|
||||
DIV_ROUND_UP(sseu->eu_total,
|
||||
sseu_subslice_total(sseu)) : 0;
|
||||
|
||||
/*
|
||||
* BDW supports slice power gating on devices with more than
|
||||
* one slice.
|
||||
*/
|
||||
info->has_slice_pg = (info->slice_total > 1);
|
||||
info->has_subslice_pg = 0;
|
||||
info->has_eu_pg = 0;
|
||||
sseu->has_slice_pg = hweight8(sseu->slice_mask) > 1;
|
||||
sseu->has_subslice_pg = 0;
|
||||
sseu->has_eu_pg = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -374,15 +370,19 @@ void intel_device_info_runtime_init(struct drm_i915_private *dev_priv)
|
||||
if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
|
||||
info->has_snoop = false;
|
||||
|
||||
DRM_DEBUG_DRIVER("slice total: %u\n", info->slice_total);
|
||||
DRM_DEBUG_DRIVER("subslice total: %u\n", info->subslice_total);
|
||||
DRM_DEBUG_DRIVER("subslice per slice: %u\n", info->subslice_per_slice);
|
||||
DRM_DEBUG_DRIVER("EU total: %u\n", info->eu_total);
|
||||
DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->eu_per_subslice);
|
||||
DRM_DEBUG_DRIVER("slice mask: %04x\n", info->sseu.slice_mask);
|
||||
DRM_DEBUG_DRIVER("slice total: %u\n", hweight8(info->sseu.slice_mask));
|
||||
DRM_DEBUG_DRIVER("subslice total: %u\n",
|
||||
sseu_subslice_total(&info->sseu));
|
||||
DRM_DEBUG_DRIVER("subslice mask %04x\n", info->sseu.subslice_mask);
|
||||
DRM_DEBUG_DRIVER("subslice per slice: %u\n",
|
||||
hweight8(info->sseu.subslice_mask));
|
||||
DRM_DEBUG_DRIVER("EU total: %u\n", info->sseu.eu_total);
|
||||
DRM_DEBUG_DRIVER("EU per subslice: %u\n", info->sseu.eu_per_subslice);
|
||||
DRM_DEBUG_DRIVER("has slice power gating: %s\n",
|
||||
info->has_slice_pg ? "y" : "n");
|
||||
info->sseu.has_slice_pg ? "y" : "n");
|
||||
DRM_DEBUG_DRIVER("has subslice power gating: %s\n",
|
||||
info->has_subslice_pg ? "y" : "n");
|
||||
info->sseu.has_subslice_pg ? "y" : "n");
|
||||
DRM_DEBUG_DRIVER("has EU power gating: %s\n",
|
||||
info->has_eu_pg ? "y" : "n");
|
||||
info->sseu.has_eu_pg ? "y" : "n");
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -190,6 +190,29 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
|
||||
return (max_link_clock * max_lanes * 8) / 10;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_encoder *encoder = &intel_dig_port->base;
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
int max_dotclk = dev_priv->max_dotclk_freq;
|
||||
int ds_max_dotclk;
|
||||
|
||||
int type = intel_dp->downstream_ports[0] & DP_DS_PORT_TYPE_MASK;
|
||||
|
||||
if (type != DP_DS_PORT_TYPE_VGA)
|
||||
return max_dotclk;
|
||||
|
||||
ds_max_dotclk = drm_dp_downstream_max_clock(intel_dp->dpcd,
|
||||
intel_dp->downstream_ports);
|
||||
|
||||
if (ds_max_dotclk != 0)
|
||||
max_dotclk = min(max_dotclk, ds_max_dotclk);
|
||||
|
||||
return max_dotclk;
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
intel_dp_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
@ -199,7 +222,9 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
|
||||
int target_clock = mode->clock;
|
||||
int max_rate, mode_rate, max_lanes, max_link_clock;
|
||||
int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
|
||||
int max_dotclk;
|
||||
|
||||
max_dotclk = intel_dp_downstream_max_dotclock(intel_dp);
|
||||
|
||||
if (is_edp(intel_dp) && fixed_mode) {
|
||||
if (mode->hdisplay > fixed_mode->hdisplay)
|
||||
@ -1243,7 +1268,7 @@ intel_dp_aux_fini(struct intel_dp *intel_dp)
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
|
||||
intel_dp_aux_init(struct intel_dp *intel_dp)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
enum port port = intel_dig_port->port;
|
||||
@ -1419,6 +1444,44 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
|
||||
DRM_DEBUG_KMS("common rates: %s\n", str);
|
||||
}
|
||||
|
||||
static void intel_dp_print_hw_revision(struct intel_dp *intel_dp)
|
||||
{
|
||||
uint8_t rev;
|
||||
int len;
|
||||
|
||||
if ((drm_debug & DRM_UT_KMS) == 0)
|
||||
return;
|
||||
|
||||
if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DWN_STRM_PORT_PRESENT))
|
||||
return;
|
||||
|
||||
len = drm_dp_dpcd_read(&intel_dp->aux, DP_BRANCH_HW_REV, &rev, 1);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("sink hw revision: %d.%d\n", (rev & 0xf0) >> 4, rev & 0xf);
|
||||
}
|
||||
|
||||
static void intel_dp_print_sw_revision(struct intel_dp *intel_dp)
|
||||
{
|
||||
uint8_t rev[2];
|
||||
int len;
|
||||
|
||||
if ((drm_debug & DRM_UT_KMS) == 0)
|
||||
return;
|
||||
|
||||
if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
DP_DWN_STRM_PORT_PRESENT))
|
||||
return;
|
||||
|
||||
len = drm_dp_dpcd_read(&intel_dp->aux, DP_BRANCH_SW_REV, &rev, 2);
|
||||
if (len < 0)
|
||||
return;
|
||||
|
||||
DRM_DEBUG_KMS("sink sw revision: %d.%d\n", rev[0], rev[1]);
|
||||
}
|
||||
|
||||
static int rate_to_index(int find, const int *rates)
|
||||
{
|
||||
int i = 0;
|
||||
@ -1461,9 +1524,24 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_dp_compute_bpp(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
int bpp, bpc;
|
||||
|
||||
bpp = pipe_config->pipe_bpp;
|
||||
bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, intel_dp->downstream_ports);
|
||||
|
||||
if (bpc > 0)
|
||||
bpp = min(bpp, 3*bpc);
|
||||
|
||||
return bpp;
|
||||
}
|
||||
|
||||
bool
|
||||
intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1526,7 +1604,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
|
||||
/* Walk through all bpp values. Luckily they're all nicely spaced with 2
|
||||
* bpc in between. */
|
||||
bpp = pipe_config->pipe_bpp;
|
||||
bpp = intel_dp_compute_bpp(intel_dp, pipe_config);
|
||||
if (is_edp(intel_dp)) {
|
||||
|
||||
/* Get bpp from vbt only for panels that dont have bpp in edid */
|
||||
@ -1640,23 +1718,28 @@ found:
|
||||
}
|
||||
|
||||
void intel_dp_set_link_params(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *pipe_config)
|
||||
int link_rate, uint8_t lane_count,
|
||||
bool link_mst)
|
||||
{
|
||||
intel_dp->link_rate = pipe_config->port_clock;
|
||||
intel_dp->lane_count = pipe_config->lane_count;
|
||||
intel_dp->link_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST);
|
||||
intel_dp->link_rate = link_rate;
|
||||
intel_dp->lane_count = lane_count;
|
||||
intel_dp->link_mst = link_mst;
|
||||
}
|
||||
|
||||
static void intel_dp_prepare(struct intel_encoder *encoder)
|
||||
static void intel_dp_prepare(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
enum port port = dp_to_dig_port(intel_dp)->port;
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
|
||||
intel_dp_set_link_params(intel_dp, crtc->config);
|
||||
intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
|
||||
pipe_config->lane_count,
|
||||
intel_crtc_has_type(pipe_config,
|
||||
INTEL_OUTPUT_DP_MST));
|
||||
|
||||
/*
|
||||
* There are four kinds of DP registers:
|
||||
@ -1682,7 +1765,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
|
||||
|
||||
/* Handle DP bits in common between all three register formats */
|
||||
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
|
||||
intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count);
|
||||
intel_dp->DP |= DP_PORT_WIDTH(pipe_config->lane_count);
|
||||
|
||||
/* Split out the IBX/CPU vs CPT settings */
|
||||
|
||||
@ -1710,7 +1793,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
|
||||
I915_WRITE(TRANS_DP_CTL(crtc->pipe), trans_dp);
|
||||
} else {
|
||||
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
|
||||
!IS_CHERRYVIEW(dev) && crtc->config->limited_color_range)
|
||||
!IS_CHERRYVIEW(dev) && pipe_config->limited_color_range)
|
||||
intel_dp->DP |= DP_COLOR_RANGE_16_235;
|
||||
|
||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||
@ -2249,10 +2332,10 @@ static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state)
|
||||
#define assert_edp_pll_enabled(d) assert_edp_pll((d), true)
|
||||
#define assert_edp_pll_disabled(d) assert_edp_pll((d), false)
|
||||
|
||||
static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
|
||||
static void ironlake_edp_pll_on(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
|
||||
struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc);
|
||||
struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
|
||||
assert_pipe_disabled(dev_priv, crtc->pipe);
|
||||
@ -2260,11 +2343,11 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
|
||||
assert_edp_pll_disabled(dev_priv);
|
||||
|
||||
DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n",
|
||||
crtc->config->port_clock);
|
||||
pipe_config->port_clock);
|
||||
|
||||
intel_dp->DP &= ~DP_PLL_FREQ_MASK;
|
||||
|
||||
if (crtc->config->port_clock == 162000)
|
||||
if (pipe_config->port_clock == 162000)
|
||||
intel_dp->DP |= DP_PLL_FREQ_162MHZ;
|
||||
else
|
||||
intel_dp->DP |= DP_PLL_FREQ_270MHZ;
|
||||
@ -2473,16 +2556,17 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_disable_dp(struct intel_encoder *encoder)
|
||||
static void intel_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
||||
if (crtc->config->has_audio)
|
||||
if (old_crtc_state->has_audio)
|
||||
intel_audio_codec_disable(encoder);
|
||||
|
||||
if (HAS_PSR(dev) && !HAS_DDI(dev))
|
||||
if (HAS_PSR(dev_priv) && !HAS_DDI(dev_priv))
|
||||
intel_psr_disable(intel_dp);
|
||||
|
||||
/* Make sure the panel is off before trying to change the mode. But also
|
||||
@ -2493,11 +2577,13 @@ static void intel_disable_dp(struct intel_encoder *encoder)
|
||||
intel_edp_panel_off(intel_dp);
|
||||
|
||||
/* disable the port before the pipe on g4x */
|
||||
if (INTEL_INFO(dev)->gen < 5)
|
||||
if (INTEL_GEN(dev_priv) < 5)
|
||||
intel_dp_link_down(intel_dp);
|
||||
}
|
||||
|
||||
static void ilk_post_disable_dp(struct intel_encoder *encoder)
|
||||
static void ilk_post_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
enum port port = dp_to_dig_port(intel_dp)->port;
|
||||
@ -2509,14 +2595,18 @@ static void ilk_post_disable_dp(struct intel_encoder *encoder)
|
||||
ironlake_edp_pll_off(intel_dp);
|
||||
}
|
||||
|
||||
static void vlv_post_disable_dp(struct intel_encoder *encoder)
|
||||
static void vlv_post_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
|
||||
intel_dp_link_down(intel_dp);
|
||||
}
|
||||
|
||||
static void chv_post_disable_dp(struct intel_encoder *encoder)
|
||||
static void chv_post_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
@ -2542,6 +2632,10 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
enum port port = intel_dig_port->port;
|
||||
|
||||
if (dp_train_pat & DP_TRAINING_PATTERN_MASK)
|
||||
DRM_DEBUG_KMS("Using DP training pattern TPS%d\n",
|
||||
dp_train_pat & DP_TRAINING_PATTERN_MASK);
|
||||
|
||||
if (HAS_DDI(dev)) {
|
||||
uint32_t temp = I915_READ(DP_TP_CTL(port));
|
||||
|
||||
@ -2583,7 +2677,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
*DP |= DP_LINK_TRAIN_PAT_2_CPT;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_3:
|
||||
DRM_ERROR("DP training pattern 3 not supported\n");
|
||||
DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
|
||||
*DP |= DP_LINK_TRAIN_PAT_2_CPT;
|
||||
break;
|
||||
}
|
||||
@ -2608,7 +2702,7 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
if (IS_CHERRYVIEW(dev)) {
|
||||
*DP |= DP_LINK_TRAIN_PAT_3_CHV;
|
||||
} else {
|
||||
DRM_ERROR("DP training pattern 3 not supported\n");
|
||||
DRM_DEBUG_KMS("TPS3 not supported, using TPS2 instead\n");
|
||||
*DP |= DP_LINK_TRAIN_PAT_2;
|
||||
}
|
||||
break;
|
||||
@ -2616,19 +2710,15 @@ _intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_dp_enable_port(struct intel_dp *intel_dp)
|
||||
static void intel_dp_enable_port(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *old_crtc_state)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc =
|
||||
to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc);
|
||||
|
||||
/* enable with pattern 1 (as per spec) */
|
||||
_intel_dp_set_link_train(intel_dp, &intel_dp->DP,
|
||||
DP_TRAINING_PATTERN_1);
|
||||
|
||||
I915_WRITE(intel_dp->output_reg, intel_dp->DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
intel_dp_program_link_training_pattern(intel_dp, DP_TRAINING_PATTERN_1);
|
||||
|
||||
/*
|
||||
* Magic for VLV/CHV. We _must_ first set up the register
|
||||
@ -2637,14 +2727,15 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp)
|
||||
* fail when the power sequencer is freshly used for this port.
|
||||
*/
|
||||
intel_dp->DP |= DP_PORT_EN;
|
||||
if (crtc->config->has_audio)
|
||||
if (old_crtc_state->has_audio)
|
||||
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
|
||||
|
||||
I915_WRITE(intel_dp->output_reg, intel_dp->DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
}
|
||||
|
||||
static void intel_enable_dp(struct intel_encoder *encoder)
|
||||
static void intel_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
@ -2661,7 +2752,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
vlv_init_panel_power_sequencer(intel_dp);
|
||||
|
||||
intel_dp_enable_port(intel_dp);
|
||||
intel_dp_enable_port(intel_dp, pipe_config);
|
||||
|
||||
edp_panel_vdd_on(intel_dp);
|
||||
edp_panel_on(intel_dp);
|
||||
@ -2673,7 +2764,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
|
||||
unsigned int lane_mask = 0x0;
|
||||
|
||||
if (IS_CHERRYVIEW(dev))
|
||||
lane_mask = intel_dp_unused_lane_mask(crtc->config->lane_count);
|
||||
lane_mask = intel_dp_unused_lane_mask(pipe_config->lane_count);
|
||||
|
||||
vlv_wait_port_ready(dev_priv, dp_to_dig_port(intel_dp),
|
||||
lane_mask);
|
||||
@ -2683,22 +2774,26 @@ static void intel_enable_dp(struct intel_encoder *encoder)
|
||||
intel_dp_start_link_train(intel_dp);
|
||||
intel_dp_stop_link_train(intel_dp);
|
||||
|
||||
if (crtc->config->has_audio) {
|
||||
if (pipe_config->has_audio) {
|
||||
DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
|
||||
pipe_name(pipe));
|
||||
intel_audio_codec_enable(encoder);
|
||||
}
|
||||
}
|
||||
|
||||
static void g4x_enable_dp(struct intel_encoder *encoder)
|
||||
static void g4x_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
|
||||
intel_enable_dp(encoder);
|
||||
intel_enable_dp(encoder, pipe_config);
|
||||
intel_edp_backlight_on(intel_dp);
|
||||
}
|
||||
|
||||
static void vlv_enable_dp(struct intel_encoder *encoder)
|
||||
static void vlv_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
|
||||
@ -2706,16 +2801,18 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
|
||||
intel_psr_enable(intel_dp);
|
||||
}
|
||||
|
||||
static void g4x_pre_enable_dp(struct intel_encoder *encoder)
|
||||
static void g4x_pre_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
|
||||
enum port port = dp_to_dig_port(intel_dp)->port;
|
||||
|
||||
intel_dp_prepare(encoder);
|
||||
intel_dp_prepare(encoder, pipe_config);
|
||||
|
||||
/* Only ilk+ has port A */
|
||||
if (port == PORT_A)
|
||||
ironlake_edp_pll_on(intel_dp);
|
||||
ironlake_edp_pll_on(intel_dp, pipe_config);
|
||||
}
|
||||
|
||||
static void vlv_detach_power_sequencer(struct intel_dp *intel_dp)
|
||||
@ -2821,38 +2918,48 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp)
|
||||
intel_dp_init_panel_power_sequencer_registers(dev, intel_dp);
|
||||
}
|
||||
|
||||
static void vlv_pre_enable_dp(struct intel_encoder *encoder)
|
||||
static void vlv_pre_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
vlv_phy_pre_encoder_enable(encoder);
|
||||
|
||||
intel_enable_dp(encoder);
|
||||
intel_enable_dp(encoder, pipe_config);
|
||||
}
|
||||
|
||||
static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
|
||||
static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
intel_dp_prepare(encoder);
|
||||
intel_dp_prepare(encoder, pipe_config);
|
||||
|
||||
vlv_phy_pre_pll_enable(encoder);
|
||||
}
|
||||
|
||||
static void chv_pre_enable_dp(struct intel_encoder *encoder)
|
||||
static void chv_pre_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
chv_phy_pre_encoder_enable(encoder);
|
||||
|
||||
intel_enable_dp(encoder);
|
||||
intel_enable_dp(encoder, pipe_config);
|
||||
|
||||
/* Second common lane will stay alive on its own now */
|
||||
chv_phy_release_cl2_override(encoder);
|
||||
}
|
||||
|
||||
static void chv_dp_pre_pll_enable(struct intel_encoder *encoder)
|
||||
static void chv_dp_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
intel_dp_prepare(encoder);
|
||||
intel_dp_prepare(encoder, pipe_config);
|
||||
|
||||
chv_phy_pre_pll_enable(encoder);
|
||||
}
|
||||
|
||||
static void chv_dp_post_pll_disable(struct intel_encoder *encoder)
|
||||
static void chv_dp_post_pll_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
chv_phy_post_pll_disable(encoder);
|
||||
}
|
||||
@ -4171,7 +4278,7 @@ static bool bxt_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
*
|
||||
* Return %true if @port is connected, %false otherwise.
|
||||
*/
|
||||
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
static bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
struct intel_digital_port *port)
|
||||
{
|
||||
if (HAS_PCH_IBX(dev_priv))
|
||||
@ -4282,6 +4389,9 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
|
||||
|
||||
intel_dp_probe_oui(intel_dp);
|
||||
|
||||
intel_dp_print_hw_revision(intel_dp);
|
||||
intel_dp_print_sw_revision(intel_dp);
|
||||
|
||||
intel_dp_configure_mst(intel_dp);
|
||||
|
||||
if (intel_dp->is_mst) {
|
||||
@ -5022,7 +5132,8 @@ static void intel_dp_pps_init(struct drm_device *dev,
|
||||
|
||||
/**
|
||||
* intel_dp_set_drrs_state - program registers for RR switch to take effect
|
||||
* @dev: DRM device
|
||||
* @dev_priv: i915 device
|
||||
* @crtc_state: a pointer to the active intel_crtc_state
|
||||
* @refresh_rate: RR to be programmed
|
||||
*
|
||||
* This function gets called when refresh rate (RR) has to be changed from
|
||||
@ -5032,14 +5143,14 @@ static void intel_dp_pps_init(struct drm_device *dev,
|
||||
*
|
||||
* The caller of this function needs to take a lock on dev_priv->drrs.
|
||||
*/
|
||||
static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
||||
static void intel_dp_set_drrs_state(struct drm_i915_private *dev_priv,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
int refresh_rate)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_encoder *encoder;
|
||||
struct intel_digital_port *dig_port = NULL;
|
||||
struct intel_dp *intel_dp = dev_priv->drrs.dp;
|
||||
struct intel_crtc_state *config = NULL;
|
||||
struct intel_crtc *intel_crtc = NULL;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc);
|
||||
enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
|
||||
|
||||
if (refresh_rate <= 0) {
|
||||
@ -5066,8 +5177,6 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
||||
return;
|
||||
}
|
||||
|
||||
config = intel_crtc->config;
|
||||
|
||||
if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
|
||||
DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
|
||||
return;
|
||||
@ -5083,12 +5192,12 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!intel_crtc->active) {
|
||||
if (!crtc_state->base.active) {
|
||||
DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (INTEL_INFO(dev)->gen >= 8 && !IS_CHERRYVIEW(dev)) {
|
||||
if (INTEL_GEN(dev_priv) >= 8 && !IS_CHERRYVIEW(dev_priv)) {
|
||||
switch (index) {
|
||||
case DRRS_HIGH_RR:
|
||||
intel_dp_set_m_n(intel_crtc, M1_N1);
|
||||
@ -5100,18 +5209,18 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
||||
default:
|
||||
DRM_ERROR("Unsupported refreshrate type\n");
|
||||
}
|
||||
} else if (INTEL_INFO(dev)->gen > 6) {
|
||||
i915_reg_t reg = PIPECONF(intel_crtc->config->cpu_transcoder);
|
||||
} else if (INTEL_GEN(dev_priv) > 6) {
|
||||
i915_reg_t reg = PIPECONF(crtc_state->cpu_transcoder);
|
||||
u32 val;
|
||||
|
||||
val = I915_READ(reg);
|
||||
if (index > DRRS_HIGH_RR) {
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
val |= PIPECONF_EDP_RR_MODE_SWITCH_VLV;
|
||||
else
|
||||
val |= PIPECONF_EDP_RR_MODE_SWITCH;
|
||||
} else {
|
||||
if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
|
||||
if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
|
||||
val &= ~PIPECONF_EDP_RR_MODE_SWITCH_VLV;
|
||||
else
|
||||
val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
|
||||
@ -5127,18 +5236,17 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
|
||||
/**
|
||||
* intel_edp_drrs_enable - init drrs struct if supported
|
||||
* @intel_dp: DP struct
|
||||
* @crtc_state: A pointer to the active crtc state.
|
||||
*
|
||||
* Initializes frontbuffer_bits and drrs.dp
|
||||
*/
|
||||
void intel_edp_drrs_enable(struct intel_dp *intel_dp)
|
||||
void intel_edp_drrs_enable(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_crtc *crtc = dig_port->base.base.crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
if (!intel_crtc->config->has_drrs) {
|
||||
if (!crtc_state->has_drrs) {
|
||||
DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
|
||||
return;
|
||||
}
|
||||
@ -5160,17 +5268,16 @@ unlock:
|
||||
/**
|
||||
* intel_edp_drrs_disable - Disable DRRS
|
||||
* @intel_dp: DP struct
|
||||
* @old_crtc_state: Pointer to old crtc_state.
|
||||
*
|
||||
*/
|
||||
void intel_edp_drrs_disable(struct intel_dp *intel_dp)
|
||||
void intel_edp_drrs_disable(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *old_crtc_state)
|
||||
{
|
||||
struct drm_device *dev = intel_dp_to_dev(intel_dp);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
|
||||
struct drm_crtc *crtc = dig_port->base.base.crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
if (!intel_crtc->config->has_drrs)
|
||||
if (!old_crtc_state->has_drrs)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev_priv->drrs.mutex);
|
||||
@ -5180,9 +5287,8 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp)
|
||||
}
|
||||
|
||||
if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
|
||||
intel_dp_set_drrs_state(&dev_priv->drm,
|
||||
intel_dp->attached_connector->panel.
|
||||
fixed_mode->vrefresh);
|
||||
intel_dp_set_drrs_state(dev_priv, old_crtc_state,
|
||||
intel_dp->attached_connector->panel.fixed_mode->vrefresh);
|
||||
|
||||
dev_priv->drrs.dp = NULL;
|
||||
mutex_unlock(&dev_priv->drrs.mutex);
|
||||
@ -5211,10 +5317,12 @@ static void intel_edp_drrs_downclock_work(struct work_struct *work)
|
||||
if (dev_priv->drrs.busy_frontbuffer_bits)
|
||||
goto unlock;
|
||||
|
||||
if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
|
||||
intel_dp_set_drrs_state(&dev_priv->drm,
|
||||
intel_dp->attached_connector->panel.
|
||||
downclock_mode->vrefresh);
|
||||
if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR) {
|
||||
struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
|
||||
|
||||
intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
|
||||
intel_dp->attached_connector->panel.downclock_mode->vrefresh);
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev_priv->drrs.mutex);
|
||||
@ -5255,9 +5363,8 @@ void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
|
||||
|
||||
/* invalidate means busy screen hence upclock */
|
||||
if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
|
||||
intel_dp_set_drrs_state(&dev_priv->drm,
|
||||
dev_priv->drrs.dp->attached_connector->panel.
|
||||
fixed_mode->vrefresh);
|
||||
intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
|
||||
dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
|
||||
|
||||
mutex_unlock(&dev_priv->drrs.mutex);
|
||||
}
|
||||
@ -5299,9 +5406,8 @@ void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
|
||||
|
||||
/* flush means busy screen hence upclock */
|
||||
if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
|
||||
intel_dp_set_drrs_state(&dev_priv->drm,
|
||||
dev_priv->drrs.dp->attached_connector->panel.
|
||||
fixed_mode->vrefresh);
|
||||
intel_dp_set_drrs_state(dev_priv, to_intel_crtc(crtc)->config,
|
||||
dev_priv->drrs.dp->attached_connector->panel.fixed_mode->vrefresh);
|
||||
|
||||
/*
|
||||
* flush also means no more activity hence schedule downclock, if all
|
||||
@ -5598,7 +5704,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
intel_dp_aux_init(intel_dp, intel_connector);
|
||||
intel_dp_aux_init(intel_dp);
|
||||
|
||||
INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
|
||||
edp_panel_vdd_work);
|
||||
|
@ -23,6 +23,15 @@
|
||||
|
||||
#include "intel_drv.h"
|
||||
|
||||
static void
|
||||
intel_dp_dump_link_status(const uint8_t link_status[DP_LINK_STATUS_SIZE])
|
||||
{
|
||||
|
||||
DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
|
||||
link_status[0], link_status[1], link_status[2],
|
||||
link_status[3], link_status[4], link_status[5]);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_get_adjust_train(struct intel_dp *intel_dp,
|
||||
const uint8_t link_status[DP_LINK_STATUS_SIZE])
|
||||
@ -103,13 +112,24 @@ intel_dp_update_link_train(struct intel_dp *intel_dp)
|
||||
return ret == intel_dp->lane_count;
|
||||
}
|
||||
|
||||
static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
|
||||
{
|
||||
int lane;
|
||||
|
||||
for (lane = 0; lane < intel_dp->lane_count; lane++)
|
||||
if ((intel_dp->train_set[lane] &
|
||||
DP_TRAIN_MAX_SWING_REACHED) == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Enable corresponding port and start training pattern 1 */
|
||||
static void
|
||||
static bool
|
||||
intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
|
||||
{
|
||||
int i;
|
||||
uint8_t voltage;
|
||||
int voltage_tries, loop_tries;
|
||||
int voltage_tries, max_vswing_tries;
|
||||
uint8_t link_config[2];
|
||||
uint8_t link_bw, rate_select;
|
||||
|
||||
@ -125,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
|
||||
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
|
||||
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
|
||||
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
|
||||
|
||||
if (intel_dp->num_sink_rates)
|
||||
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
|
||||
&rate_select, 1);
|
||||
@ -140,60 +161,54 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
|
||||
DP_TRAINING_PATTERN_1 |
|
||||
DP_LINK_SCRAMBLING_DISABLE)) {
|
||||
DRM_ERROR("failed to enable link training\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
voltage = 0xff;
|
||||
voltage_tries = 0;
|
||||
loop_tries = 0;
|
||||
voltage_tries = 1;
|
||||
max_vswing_tries = 0;
|
||||
for (;;) {
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
|
||||
|
||||
if (!intel_dp_get_link_status(intel_dp, link_status)) {
|
||||
DRM_ERROR("failed to get link status\n");
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
|
||||
DRM_DEBUG_KMS("clock recovery OK\n");
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check to see if we've tried the max voltage */
|
||||
for (i = 0; i < intel_dp->lane_count; i++)
|
||||
if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
|
||||
break;
|
||||
if (i == intel_dp->lane_count) {
|
||||
++loop_tries;
|
||||
if (loop_tries == 5) {
|
||||
DRM_ERROR("too many full retries, give up\n");
|
||||
break;
|
||||
}
|
||||
intel_dp_reset_link_train(intel_dp,
|
||||
DP_TRAINING_PATTERN_1 |
|
||||
DP_LINK_SCRAMBLING_DISABLE);
|
||||
voltage_tries = 0;
|
||||
continue;
|
||||
if (voltage_tries == 5) {
|
||||
DRM_DEBUG_KMS("Same voltage tried 5 times\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (max_vswing_tries == 1) {
|
||||
DRM_DEBUG_KMS("Max Voltage Swing reached\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check to see if we've tried the same voltage 5 times */
|
||||
if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
|
||||
++voltage_tries;
|
||||
if (voltage_tries == 5) {
|
||||
DRM_ERROR("too many voltage retries, give up\n");
|
||||
break;
|
||||
}
|
||||
} else
|
||||
voltage_tries = 0;
|
||||
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
|
||||
|
||||
/* Update training set as requested by target */
|
||||
intel_get_adjust_train(intel_dp, link_status);
|
||||
if (!intel_dp_update_link_train(intel_dp)) {
|
||||
DRM_ERROR("failed to update link training\n");
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
|
||||
voltage)
|
||||
++voltage_tries;
|
||||
else
|
||||
voltage_tries = 1;
|
||||
|
||||
if (intel_dp_link_max_vswing_reached(intel_dp))
|
||||
++max_vswing_tries;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,12 +244,12 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
|
||||
return training_pattern;
|
||||
}
|
||||
|
||||
static void
|
||||
static bool
|
||||
intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
||||
{
|
||||
bool channel_eq = false;
|
||||
int tries, cr_tries;
|
||||
int tries;
|
||||
u32 training_pattern;
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
training_pattern = intel_dp_training_pattern(intel_dp);
|
||||
|
||||
@ -243,19 +258,11 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
||||
training_pattern |
|
||||
DP_LINK_SCRAMBLING_DISABLE)) {
|
||||
DRM_ERROR("failed to start channel equalization\n");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
tries = 0;
|
||||
cr_tries = 0;
|
||||
channel_eq = false;
|
||||
for (;;) {
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
if (cr_tries > 5) {
|
||||
DRM_ERROR("failed to train DP, aborting\n");
|
||||
break;
|
||||
}
|
||||
intel_dp->channel_eq_status = false;
|
||||
for (tries = 0; tries < 5; tries++) {
|
||||
|
||||
drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
|
||||
if (!intel_dp_get_link_status(intel_dp, link_status)) {
|
||||
@ -266,44 +273,38 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
|
||||
/* Make sure clock is still ok */
|
||||
if (!drm_dp_clock_recovery_ok(link_status,
|
||||
intel_dp->lane_count)) {
|
||||
intel_dp_link_training_clock_recovery(intel_dp);
|
||||
intel_dp_set_link_train(intel_dp,
|
||||
training_pattern |
|
||||
DP_LINK_SCRAMBLING_DISABLE);
|
||||
cr_tries++;
|
||||
continue;
|
||||
intel_dp_dump_link_status(link_status);
|
||||
DRM_DEBUG_KMS("Clock recovery check failed, cannot "
|
||||
"continue channel equalization\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (drm_dp_channel_eq_ok(link_status,
|
||||
intel_dp->lane_count)) {
|
||||
channel_eq = true;
|
||||
intel_dp->channel_eq_status = true;
|
||||
DRM_DEBUG_KMS("Channel EQ done. DP Training "
|
||||
"successful\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Try 5 times, then try clock recovery if that fails */
|
||||
if (tries > 5) {
|
||||
intel_dp_link_training_clock_recovery(intel_dp);
|
||||
intel_dp_set_link_train(intel_dp,
|
||||
training_pattern |
|
||||
DP_LINK_SCRAMBLING_DISABLE);
|
||||
tries = 0;
|
||||
cr_tries++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update training set as requested by target */
|
||||
intel_get_adjust_train(intel_dp, link_status);
|
||||
if (!intel_dp_update_link_train(intel_dp)) {
|
||||
DRM_ERROR("failed to update link training\n");
|
||||
break;
|
||||
}
|
||||
++tries;
|
||||
}
|
||||
|
||||
/* Try 5 times, else fail and try at lower BW */
|
||||
if (tries == 5) {
|
||||
intel_dp_dump_link_status(link_status);
|
||||
DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
|
||||
}
|
||||
|
||||
intel_dp_set_idle_link_train(intel_dp);
|
||||
|
||||
if (channel_eq)
|
||||
DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
|
||||
return intel_dp->channel_eq_status;
|
||||
|
||||
}
|
||||
|
||||
void intel_dp_stop_link_train(struct intel_dp *intel_dp)
|
||||
|
@ -31,18 +31,16 @@
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct drm_atomic_state *state;
|
||||
int bpp, i;
|
||||
int bpp;
|
||||
int lane_count, slots;
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
struct drm_connector *drm_connector;
|
||||
struct intel_connector *connector, *found = NULL;
|
||||
struct drm_connector_state *connector_state;
|
||||
int mst_pbn;
|
||||
|
||||
pipe_config->dp_encoder_is_mst = true;
|
||||
@ -54,7 +52,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
*/
|
||||
lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
|
||||
|
||||
|
||||
pipe_config->lane_count = lane_count;
|
||||
|
||||
pipe_config->pipe_bpp = 24;
|
||||
@ -62,20 +59,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
|
||||
state = pipe_config->base.state;
|
||||
|
||||
for_each_connector_in_state(state, drm_connector, connector_state, i) {
|
||||
connector = to_intel_connector(drm_connector);
|
||||
|
||||
if (connector_state->best_encoder == &encoder->base) {
|
||||
found = connector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
DRM_ERROR("can't find connector\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp);
|
||||
|
||||
pipe_config->pbn = mst_pbn;
|
||||
@ -92,16 +75,20 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
|
||||
|
||||
}
|
||||
|
||||
static void intel_mst_disable_dp(struct intel_encoder *encoder)
|
||||
static void intel_mst_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(old_conn_state->connector);
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
|
||||
|
||||
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->connector->port);
|
||||
drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, connector->port);
|
||||
|
||||
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
|
||||
if (ret) {
|
||||
@ -109,11 +96,15 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
|
||||
static void intel_mst_post_disable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(old_conn_state->connector);
|
||||
|
||||
DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
|
||||
|
||||
@ -122,59 +113,51 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder)
|
||||
/* and this can also fail */
|
||||
drm_dp_update_payload_part2(&intel_dp->mst_mgr);
|
||||
|
||||
drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->connector->port);
|
||||
drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, connector->port);
|
||||
|
||||
intel_dp->active_mst_links--;
|
||||
|
||||
intel_mst->connector = NULL;
|
||||
if (intel_dp->active_mst_links == 0) {
|
||||
intel_dig_port->base.post_disable(&intel_dig_port->base);
|
||||
intel_dig_port->base.post_disable(&intel_dig_port->base,
|
||||
NULL, NULL);
|
||||
|
||||
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
|
||||
static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum port port = intel_dig_port->port;
|
||||
struct intel_connector *connector =
|
||||
to_intel_connector(conn_state->connector);
|
||||
int ret;
|
||||
uint32_t temp;
|
||||
struct intel_connector *found = NULL, *connector;
|
||||
int slots;
|
||||
struct drm_crtc *crtc = encoder->base.crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
|
||||
for_each_intel_connector(dev, connector) {
|
||||
if (connector->base.state->best_encoder == &encoder->base) {
|
||||
found = connector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
DRM_ERROR("can't find connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* MST encoders are bound to a crtc, not to a connector,
|
||||
* force the mapping here for get_hw_state.
|
||||
*/
|
||||
found->encoder = encoder;
|
||||
connector->encoder = encoder;
|
||||
intel_mst->connector = connector;
|
||||
|
||||
DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
|
||||
|
||||
intel_mst->connector = found;
|
||||
|
||||
if (intel_dp->active_mst_links == 0) {
|
||||
intel_ddi_clk_select(&intel_dig_port->base, intel_crtc->config);
|
||||
intel_ddi_clk_select(&intel_dig_port->base,
|
||||
pipe_config->shared_dpll);
|
||||
|
||||
intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
|
||||
|
||||
intel_dp_set_link_params(intel_dp, intel_crtc->config);
|
||||
intel_dp_set_link_params(intel_dp,
|
||||
pipe_config->port_clock,
|
||||
pipe_config->lane_count,
|
||||
true);
|
||||
|
||||
intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
|
||||
|
||||
@ -185,8 +168,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
|
||||
}
|
||||
|
||||
ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
|
||||
intel_mst->connector->port,
|
||||
intel_crtc->config->pbn, &slots);
|
||||
connector->port,
|
||||
pipe_config->pbn, &slots);
|
||||
if (ret == false) {
|
||||
DRM_ERROR("failed to allocate vcpi\n");
|
||||
return;
|
||||
@ -200,13 +183,14 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
|
||||
ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr);
|
||||
}
|
||||
|
||||
static void intel_mst_enable_dp(struct intel_encoder *encoder)
|
||||
static void intel_mst_enable_dp(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_dp *intel_dp = &intel_dig_port->dp;
|
||||
struct drm_device *dev = intel_dig_port->base.base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum port port = intel_dig_port->port;
|
||||
int ret;
|
||||
|
||||
@ -239,9 +223,8 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
|
||||
{
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
struct intel_digital_port *intel_dig_port = intel_mst->primary;
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
|
||||
u32 temp, flags = 0;
|
||||
|
||||
|
@ -23,6 +23,44 @@
|
||||
|
||||
#include "intel_drv.h"
|
||||
|
||||
struct intel_shared_dpll *
|
||||
skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
|
||||
{
|
||||
struct intel_shared_dpll *pll = NULL;
|
||||
struct intel_dpll_hw_state dpll_hw_state;
|
||||
enum intel_dpll_id i;
|
||||
bool found = false;
|
||||
|
||||
if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
|
||||
return pll;
|
||||
|
||||
for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
|
||||
pll = &dev_priv->shared_dplls[i];
|
||||
|
||||
/* Only want to check enabled timings first */
|
||||
if (pll->config.crtc_mask == 0)
|
||||
continue;
|
||||
|
||||
if (memcmp(&dpll_hw_state, &pll->config.hw_state,
|
||||
sizeof(pll->config.hw_state)) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok no matching timings, maybe there's a free one? */
|
||||
for (i = DPLL_ID_SKL_DPLL1;
|
||||
((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
|
||||
pll = &dev_priv->shared_dplls[i];
|
||||
if (pll->config.crtc_mask == 0) {
|
||||
pll->config.hw_state = dpll_hw_state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
struct intel_shared_dpll *
|
||||
intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
|
||||
enum intel_dpll_id id)
|
||||
@ -452,26 +490,6 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
|
||||
return val & SPLL_PLL_ENABLE;
|
||||
}
|
||||
|
||||
static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
|
||||
{
|
||||
switch (pll->id) {
|
||||
case DPLL_ID_WRPLL1:
|
||||
return PORT_CLK_SEL_WRPLL1;
|
||||
case DPLL_ID_WRPLL2:
|
||||
return PORT_CLK_SEL_WRPLL2;
|
||||
case DPLL_ID_SPLL:
|
||||
return PORT_CLK_SEL_SPLL;
|
||||
case DPLL_ID_LCPLL_810:
|
||||
return PORT_CLK_SEL_LCPLL_810;
|
||||
case DPLL_ID_LCPLL_1350:
|
||||
return PORT_CLK_SEL_LCPLL_1350;
|
||||
case DPLL_ID_LCPLL_2700:
|
||||
return PORT_CLK_SEL_LCPLL_2700;
|
||||
default:
|
||||
return PORT_CLK_SEL_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
#define LC_FREQ 2700
|
||||
#define LC_FREQ_2K U64_C(LC_FREQ * 2000)
|
||||
|
||||
@ -687,11 +705,65 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
|
||||
*r2_out = best.r2;
|
||||
}
|
||||
|
||||
static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
|
||||
struct intel_crtc *crtc,
|
||||
struct intel_crtc_state *crtc_state)
|
||||
{
|
||||
struct intel_shared_dpll *pll;
|
||||
uint32_t val;
|
||||
unsigned int p, n2, r2;
|
||||
|
||||
hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
|
||||
|
||||
val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
|
||||
WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
|
||||
WRPLL_DIVIDER_POST(p);
|
||||
|
||||
crtc_state->dpll_hw_state.wrpll = val;
|
||||
|
||||
pll = intel_find_shared_dpll(crtc, crtc_state,
|
||||
DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
|
||||
|
||||
if (!pll)
|
||||
return NULL;
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
|
||||
int clock)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_shared_dpll *pll;
|
||||
enum intel_dpll_id pll_id;
|
||||
|
||||
switch (clock / 2) {
|
||||
case 81000:
|
||||
pll_id = DPLL_ID_LCPLL_810;
|
||||
break;
|
||||
case 135000:
|
||||
pll_id = DPLL_ID_LCPLL_1350;
|
||||
break;
|
||||
case 270000:
|
||||
pll_id = DPLL_ID_LCPLL_2700;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
|
||||
|
||||
if (!pll)
|
||||
return NULL;
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
static struct intel_shared_dpll *
|
||||
hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
struct intel_encoder *encoder)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_shared_dpll *pll;
|
||||
int clock = crtc_state->port_clock;
|
||||
|
||||
@ -699,41 +771,12 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
sizeof(crtc_state->dpll_hw_state));
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_HDMI) {
|
||||
uint32_t val;
|
||||
unsigned p, n2, r2;
|
||||
|
||||
hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
|
||||
|
||||
val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
|
||||
WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
|
||||
WRPLL_DIVIDER_POST(p);
|
||||
|
||||
crtc_state->dpll_hw_state.wrpll = val;
|
||||
|
||||
pll = intel_find_shared_dpll(crtc, crtc_state,
|
||||
DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
|
||||
pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
|
||||
|
||||
} else if (encoder->type == INTEL_OUTPUT_DP ||
|
||||
encoder->type == INTEL_OUTPUT_DP_MST ||
|
||||
encoder->type == INTEL_OUTPUT_EDP) {
|
||||
enum intel_dpll_id pll_id;
|
||||
|
||||
switch (clock / 2) {
|
||||
case 81000:
|
||||
pll_id = DPLL_ID_LCPLL_810;
|
||||
break;
|
||||
case 135000:
|
||||
pll_id = DPLL_ID_LCPLL_1350;
|
||||
break;
|
||||
case 270000:
|
||||
pll_id = DPLL_ID_LCPLL_2700;
|
||||
break;
|
||||
default:
|
||||
DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
|
||||
pll = hsw_ddi_dp_get_dpll(encoder, clock);
|
||||
|
||||
} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
|
||||
if (WARN_ON(crtc_state->port_clock / 2 != 135000))
|
||||
@ -751,14 +794,11 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
if (!pll)
|
||||
return NULL;
|
||||
|
||||
crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll);
|
||||
|
||||
intel_reference_shared_dpll(pll, crtc_state);
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
|
||||
static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
|
||||
.enable = hsw_ddi_wrpll_enable,
|
||||
.disable = hsw_ddi_wrpll_disable,
|
||||
@ -1194,67 +1234,33 @@ skip_remaining_dividers:
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct intel_shared_dpll *
|
||||
skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
struct intel_encoder *encoder)
|
||||
static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
int clock)
|
||||
{
|
||||
struct intel_shared_dpll *pll;
|
||||
uint32_t ctrl1, cfgcr1, cfgcr2;
|
||||
int clock = crtc_state->port_clock;
|
||||
struct skl_wrpll_params wrpll_params = { 0, };
|
||||
|
||||
/*
|
||||
* See comment in intel_dpll_hw_state to understand why we always use 0
|
||||
* as the DPLL id in this function.
|
||||
*/
|
||||
|
||||
ctrl1 = DPLL_CTRL1_OVERRIDE(0);
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_HDMI) {
|
||||
struct skl_wrpll_params wrpll_params = { 0, };
|
||||
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
||||
|
||||
ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
|
||||
if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
|
||||
return false;
|
||||
|
||||
if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
|
||||
return NULL;
|
||||
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
||||
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
||||
wrpll_params.dco_integer;
|
||||
|
||||
cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
|
||||
DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
|
||||
wrpll_params.dco_integer;
|
||||
|
||||
cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
|
||||
DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
|
||||
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
|
||||
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
||||
wrpll_params.central_freq;
|
||||
} else if (encoder->type == INTEL_OUTPUT_DP ||
|
||||
encoder->type == INTEL_OUTPUT_DP_MST ||
|
||||
encoder->type == INTEL_OUTPUT_EDP) {
|
||||
switch (crtc_state->port_clock / 2) {
|
||||
case 81000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
|
||||
break;
|
||||
case 135000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
|
||||
break;
|
||||
case 270000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
|
||||
break;
|
||||
/* eDP 1.4 rates */
|
||||
case 162000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
|
||||
break;
|
||||
case 108000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
|
||||
break;
|
||||
case 216000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
cfgcr1 = cfgcr2 = 0;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
|
||||
DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
|
||||
DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
|
||||
DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
|
||||
wrpll_params.central_freq;
|
||||
|
||||
memset(&crtc_state->dpll_hw_state, 0,
|
||||
sizeof(crtc_state->dpll_hw_state));
|
||||
@ -1262,6 +1268,75 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
crtc_state->dpll_hw_state.ctrl1 = ctrl1;
|
||||
crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
|
||||
crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool skl_ddi_dp_set_dpll_hw_state(int clock,
|
||||
struct intel_dpll_hw_state *dpll_hw_state)
|
||||
{
|
||||
uint32_t ctrl1;
|
||||
|
||||
/*
|
||||
* See comment in intel_dpll_hw_state to understand why we always use 0
|
||||
* as the DPLL id in this function.
|
||||
*/
|
||||
ctrl1 = DPLL_CTRL1_OVERRIDE(0);
|
||||
switch (clock / 2) {
|
||||
case 81000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
|
||||
break;
|
||||
case 135000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
|
||||
break;
|
||||
case 270000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
|
||||
break;
|
||||
/* eDP 1.4 rates */
|
||||
case 162000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
|
||||
break;
|
||||
case 108000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
|
||||
break;
|
||||
case 216000:
|
||||
ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
dpll_hw_state->ctrl1 = ctrl1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct intel_shared_dpll *
|
||||
skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
struct intel_encoder *encoder)
|
||||
{
|
||||
struct intel_shared_dpll *pll;
|
||||
int clock = crtc_state->port_clock;
|
||||
bool bret;
|
||||
struct intel_dpll_hw_state dpll_hw_state;
|
||||
|
||||
memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_HDMI) {
|
||||
bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
|
||||
if (!bret) {
|
||||
DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
|
||||
return NULL;
|
||||
}
|
||||
} else if (encoder->type == INTEL_OUTPUT_DP ||
|
||||
encoder->type == INTEL_OUTPUT_DP_MST ||
|
||||
encoder->type == INTEL_OUTPUT_EDP) {
|
||||
bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
|
||||
if (!bret) {
|
||||
DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
|
||||
return NULL;
|
||||
}
|
||||
crtc_state->dpll_hw_state = dpll_hw_state;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_EDP)
|
||||
pll = intel_find_shared_dpll(crtc, crtc_state,
|
||||
@ -1274,8 +1349,6 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
if (!pll)
|
||||
return NULL;
|
||||
|
||||
crtc_state->ddi_pll_sel = pll->id;
|
||||
|
||||
intel_reference_shared_dpll(pll, crtc_state);
|
||||
|
||||
return pll;
|
||||
@ -1484,6 +1557,8 @@ struct bxt_clk_div {
|
||||
uint32_t m2_frac;
|
||||
bool m2_frac_en;
|
||||
uint32_t n;
|
||||
|
||||
int vco;
|
||||
};
|
||||
|
||||
/* pre-calculated values for DP linkrates */
|
||||
@ -1497,56 +1572,59 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = {
|
||||
{432000, 3, 1, 32, 1677722, 1, 1}
|
||||
};
|
||||
|
||||
static struct intel_shared_dpll *
|
||||
bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
struct intel_encoder *encoder)
|
||||
static bool
|
||||
bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
|
||||
struct intel_crtc_state *crtc_state, int clock,
|
||||
struct bxt_clk_div *clk_div)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_shared_dpll *pll;
|
||||
enum intel_dpll_id i;
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
struct bxt_clk_div clk_div = {0};
|
||||
int vco = 0;
|
||||
struct dpll best_clock;
|
||||
|
||||
/* Calculate HDMI div */
|
||||
/*
|
||||
* FIXME: tie the following calculation into
|
||||
* i9xx_crtc_compute_clock
|
||||
*/
|
||||
if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
|
||||
DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
|
||||
clock, pipe_name(intel_crtc->pipe));
|
||||
return false;
|
||||
}
|
||||
|
||||
clk_div->p1 = best_clock.p1;
|
||||
clk_div->p2 = best_clock.p2;
|
||||
WARN_ON(best_clock.m1 != 2);
|
||||
clk_div->n = best_clock.n;
|
||||
clk_div->m2_int = best_clock.m2 >> 22;
|
||||
clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
|
||||
clk_div->m2_frac_en = clk_div->m2_frac != 0;
|
||||
|
||||
clk_div->vco = best_clock.vco;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
|
||||
{
|
||||
int i;
|
||||
|
||||
*clk_div = bxt_dp_clk_val[0];
|
||||
for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
|
||||
if (bxt_dp_clk_val[i].clock == clock) {
|
||||
*clk_div = bxt_dp_clk_val[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
|
||||
}
|
||||
|
||||
static bool bxt_ddi_set_dpll_hw_state(int clock,
|
||||
struct bxt_clk_div *clk_div,
|
||||
struct intel_dpll_hw_state *dpll_hw_state)
|
||||
{
|
||||
int vco = clk_div->vco;
|
||||
uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
|
||||
uint32_t lanestagger;
|
||||
int clock = crtc_state->port_clock;
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_HDMI) {
|
||||
struct dpll best_clock;
|
||||
|
||||
/* Calculate HDMI div */
|
||||
/*
|
||||
* FIXME: tie the following calculation into
|
||||
* i9xx_crtc_compute_clock
|
||||
*/
|
||||
if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
|
||||
DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
|
||||
clock, pipe_name(crtc->pipe));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
clk_div.p1 = best_clock.p1;
|
||||
clk_div.p2 = best_clock.p2;
|
||||
WARN_ON(best_clock.m1 != 2);
|
||||
clk_div.n = best_clock.n;
|
||||
clk_div.m2_int = best_clock.m2 >> 22;
|
||||
clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
|
||||
clk_div.m2_frac_en = clk_div.m2_frac != 0;
|
||||
|
||||
vco = best_clock.vco;
|
||||
} else if (encoder->type == INTEL_OUTPUT_DP ||
|
||||
encoder->type == INTEL_OUTPUT_EDP) {
|
||||
int i;
|
||||
|
||||
clk_div = bxt_dp_clk_val[0];
|
||||
for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
|
||||
if (bxt_dp_clk_val[i].clock == clock) {
|
||||
clk_div = bxt_dp_clk_val[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
|
||||
}
|
||||
|
||||
if (vco >= 6200000 && vco <= 6700000) {
|
||||
prop_coef = 4;
|
||||
@ -1566,12 +1644,9 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
targ_cnt = 9;
|
||||
} else {
|
||||
DRM_ERROR("Invalid VCO\n");
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&crtc_state->dpll_hw_state, 0,
|
||||
sizeof(crtc_state->dpll_hw_state));
|
||||
|
||||
if (clock > 270000)
|
||||
lanestagger = 0x18;
|
||||
else if (clock > 135000)
|
||||
@ -1583,35 +1658,75 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
else
|
||||
lanestagger = 0x02;
|
||||
|
||||
crtc_state->dpll_hw_state.ebb0 =
|
||||
PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
|
||||
crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
|
||||
crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
|
||||
crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
|
||||
dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
|
||||
dpll_hw_state->pll0 = clk_div->m2_int;
|
||||
dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
|
||||
dpll_hw_state->pll2 = clk_div->m2_frac;
|
||||
|
||||
if (clk_div.m2_frac_en)
|
||||
crtc_state->dpll_hw_state.pll3 =
|
||||
PORT_PLL_M2_FRAC_ENABLE;
|
||||
if (clk_div->m2_frac_en)
|
||||
dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
|
||||
|
||||
crtc_state->dpll_hw_state.pll6 =
|
||||
prop_coef | PORT_PLL_INT_COEFF(int_coef);
|
||||
crtc_state->dpll_hw_state.pll6 |=
|
||||
PORT_PLL_GAIN_CTL(gain_ctl);
|
||||
dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
|
||||
dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
|
||||
|
||||
crtc_state->dpll_hw_state.pll8 = targ_cnt;
|
||||
dpll_hw_state->pll8 = targ_cnt;
|
||||
|
||||
crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
|
||||
dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
|
||||
|
||||
crtc_state->dpll_hw_state.pll10 =
|
||||
dpll_hw_state->pll10 =
|
||||
PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
|
||||
| PORT_PLL_DCO_AMP_OVR_EN_H;
|
||||
|
||||
crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
|
||||
dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
|
||||
|
||||
crtc_state->dpll_hw_state.pcsdw12 =
|
||||
LANESTAGGER_STRAP_OVRD | lanestagger;
|
||||
dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
|
||||
|
||||
intel_dig_port = enc_to_dig_port(&encoder->base);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bxt_ddi_dp_set_dpll_hw_state(int clock,
|
||||
struct intel_dpll_hw_state *dpll_hw_state)
|
||||
{
|
||||
struct bxt_clk_div clk_div = {0};
|
||||
|
||||
bxt_ddi_dp_pll_dividers(clock, &clk_div);
|
||||
|
||||
return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
|
||||
}
|
||||
|
||||
static struct intel_shared_dpll *
|
||||
bxt_get_dpll(struct intel_crtc *crtc,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
struct intel_encoder *encoder)
|
||||
{
|
||||
struct bxt_clk_div clk_div = {0};
|
||||
struct intel_dpll_hw_state dpll_hw_state = {0};
|
||||
struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
|
||||
struct intel_digital_port *intel_dig_port;
|
||||
struct intel_shared_dpll *pll;
|
||||
int i, clock = crtc_state->port_clock;
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_HDMI
|
||||
&& !bxt_ddi_hdmi_pll_dividers(crtc, crtc_state,
|
||||
clock, &clk_div))
|
||||
return NULL;
|
||||
|
||||
if ((encoder->type == INTEL_OUTPUT_DP ||
|
||||
encoder->type == INTEL_OUTPUT_EDP) &&
|
||||
!bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
|
||||
return NULL;
|
||||
|
||||
memset(&crtc_state->dpll_hw_state, 0,
|
||||
sizeof(crtc_state->dpll_hw_state));
|
||||
|
||||
crtc_state->dpll_hw_state = dpll_hw_state;
|
||||
|
||||
if (encoder->type == INTEL_OUTPUT_DP_MST) {
|
||||
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
|
||||
|
||||
intel_dig_port = intel_mst->primary;
|
||||
} else
|
||||
intel_dig_port = enc_to_dig_port(&encoder->base);
|
||||
|
||||
/* 1:1 mapping between ports and PLLs */
|
||||
i = (enum intel_dpll_id) intel_dig_port->port;
|
||||
@ -1622,9 +1737,6 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
|
||||
|
||||
intel_reference_shared_dpll(pll, crtc_state);
|
||||
|
||||
/* shared DPLL id 0 is DPLL A */
|
||||
crtc_state->ddi_pll_sel = pll->id;
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
|
@ -160,5 +160,20 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc);
|
||||
void intel_shared_dpll_commit(struct drm_atomic_state *state);
|
||||
void intel_shared_dpll_init(struct drm_device *dev);
|
||||
|
||||
/* BXT dpll related functions */
|
||||
bool bxt_ddi_dp_set_dpll_hw_state(int clock,
|
||||
struct intel_dpll_hw_state *dpll_hw_state);
|
||||
|
||||
|
||||
/* SKL dpll related functions */
|
||||
bool skl_ddi_dp_set_dpll_hw_state(int clock,
|
||||
struct intel_dpll_hw_state *dpll_hw_state);
|
||||
struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
|
||||
int clock);
|
||||
|
||||
|
||||
/* HSW dpll related functions */
|
||||
struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
|
||||
int clock);
|
||||
|
||||
#endif /* _INTEL_DPLL_MGR_H_ */
|
||||
|
@ -52,11 +52,15 @@
|
||||
*/
|
||||
#define _wait_for(COND, US, W) ({ \
|
||||
unsigned long timeout__ = jiffies + usecs_to_jiffies(US) + 1; \
|
||||
int ret__ = 0; \
|
||||
while (!(COND)) { \
|
||||
if (time_after(jiffies, timeout__)) { \
|
||||
if (!(COND)) \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
int ret__; \
|
||||
for (;;) { \
|
||||
bool expired__ = time_after(jiffies, timeout__); \
|
||||
if (COND) { \
|
||||
ret__ = 0; \
|
||||
break; \
|
||||
} \
|
||||
if (expired__) { \
|
||||
ret__ = -ETIMEDOUT; \
|
||||
break; \
|
||||
} \
|
||||
if ((W) && drm_can_sleep()) { \
|
||||
@ -205,14 +209,26 @@ struct intel_encoder {
|
||||
unsigned int cloneable;
|
||||
void (*hot_plug)(struct intel_encoder *);
|
||||
bool (*compute_config)(struct intel_encoder *,
|
||||
struct intel_crtc_state *);
|
||||
void (*pre_pll_enable)(struct intel_encoder *);
|
||||
void (*pre_enable)(struct intel_encoder *);
|
||||
void (*enable)(struct intel_encoder *);
|
||||
void (*mode_set)(struct intel_encoder *intel_encoder);
|
||||
void (*disable)(struct intel_encoder *);
|
||||
void (*post_disable)(struct intel_encoder *);
|
||||
void (*post_pll_disable)(struct intel_encoder *);
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*pre_pll_enable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*pre_enable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*enable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*disable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*post_disable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
void (*post_pll_disable)(struct intel_encoder *,
|
||||
struct intel_crtc_state *,
|
||||
struct drm_connector_state *);
|
||||
/* Read out the current hw state of this connector, returning true if
|
||||
* the encoder is active. If the encoder is enabled it also set the pipe
|
||||
* it is connected to in the pipe parameter. */
|
||||
@ -578,12 +594,6 @@ struct intel_crtc_state {
|
||||
/* Selected dpll when shared or NULL. */
|
||||
struct intel_shared_dpll *shared_dpll;
|
||||
|
||||
/*
|
||||
* - PORT_CLK_SEL for DDI ports on HSW/BDW.
|
||||
* - enum skl_dpll on SKL
|
||||
*/
|
||||
uint32_t ddi_pll_sel;
|
||||
|
||||
/* Actual register state of the dpll, for shared dpll cross-checking. */
|
||||
struct intel_dpll_hw_state dpll_hw_state;
|
||||
|
||||
@ -700,8 +710,8 @@ struct intel_crtc {
|
||||
|
||||
struct intel_crtc_state *config;
|
||||
|
||||
/* reset counter value when the last flip was submitted */
|
||||
unsigned int reset_counter;
|
||||
/* global reset count when the last flip was submitted */
|
||||
unsigned int reset_count;
|
||||
|
||||
/* Access to these should be protected by dev_priv->irq_lock. */
|
||||
bool cpu_fifo_underrun_disabled;
|
||||
@ -872,6 +882,7 @@ struct intel_dp {
|
||||
bool link_mst;
|
||||
bool has_audio;
|
||||
bool detect_done;
|
||||
bool channel_eq_status;
|
||||
enum hdmi_force_audio force_audio;
|
||||
bool limited_color_range;
|
||||
bool color_range_auto;
|
||||
@ -1124,7 +1135,10 @@ void intel_crt_reset(struct drm_encoder *encoder);
|
||||
|
||||
/* intel_ddi.c */
|
||||
void intel_ddi_clk_select(struct intel_encoder *encoder,
|
||||
const struct intel_crtc_state *pipe_config);
|
||||
struct intel_shared_dpll *pll);
|
||||
void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state);
|
||||
void intel_prepare_dp_ddi_buffers(struct intel_encoder *encoder);
|
||||
void hsw_fdi_link_train(struct drm_crtc *crtc);
|
||||
void intel_ddi_init(struct drm_device *dev, enum port port);
|
||||
@ -1140,7 +1154,6 @@ bool intel_ddi_pll_select(struct intel_crtc *crtc,
|
||||
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
|
||||
void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp);
|
||||
bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
|
||||
void intel_ddi_fdi_disable(struct drm_crtc *crtc);
|
||||
void intel_ddi_get_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
struct intel_encoder *
|
||||
@ -1151,7 +1164,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
|
||||
uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
|
||||
|
||||
struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
|
||||
int clock);
|
||||
unsigned int intel_fb_align_height(struct drm_device *dev,
|
||||
unsigned int height,
|
||||
uint32_t pixel_format,
|
||||
@ -1171,6 +1185,8 @@ void skl_set_preferred_cdclk_vco(struct drm_i915_private *dev_priv, int vco);
|
||||
void intel_update_rawclk(struct drm_i915_private *dev_priv);
|
||||
int vlv_get_cck_clock(struct drm_i915_private *dev_priv,
|
||||
const char *name, u32 reg, int ref_freq);
|
||||
void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv);
|
||||
void lpt_disable_iclkip(struct drm_i915_private *dev_priv);
|
||||
extern const struct drm_plane_funcs intel_plane_funcs;
|
||||
void intel_init_display_hooks(struct drm_i915_private *dev_priv);
|
||||
unsigned int intel_fb_xy_to_linear(int x, int y,
|
||||
@ -1367,7 +1383,8 @@ bool intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port
|
||||
bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
void intel_dp_set_link_params(struct intel_dp *intel_dp,
|
||||
const struct intel_crtc_state *pipe_config);
|
||||
int link_rate, uint8_t lane_count,
|
||||
bool link_mst);
|
||||
void intel_dp_start_link_train(struct intel_dp *intel_dp);
|
||||
void intel_dp_stop_link_train(struct intel_dp *intel_dp);
|
||||
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
|
||||
@ -1376,7 +1393,8 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
|
||||
void intel_dp_encoder_destroy(struct drm_encoder *encoder);
|
||||
int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
|
||||
bool intel_dp_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
bool intel_dp_is_edp(struct drm_device *dev, enum port port);
|
||||
enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
|
||||
bool long_hpd);
|
||||
@ -1394,14 +1412,14 @@ void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
|
||||
void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
|
||||
uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
|
||||
void intel_plane_destroy(struct drm_plane *plane);
|
||||
void intel_edp_drrs_enable(struct intel_dp *intel_dp);
|
||||
void intel_edp_drrs_disable(struct intel_dp *intel_dp);
|
||||
void intel_edp_drrs_enable(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
void intel_edp_drrs_disable(struct intel_dp *intel_dp,
|
||||
struct intel_crtc_state *crtc_state);
|
||||
void intel_edp_drrs_invalidate(struct drm_i915_private *dev_priv,
|
||||
unsigned int frontbuffer_bits);
|
||||
void intel_edp_drrs_flush(struct drm_i915_private *dev_priv,
|
||||
unsigned int frontbuffer_bits);
|
||||
bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
|
||||
struct intel_digital_port *port);
|
||||
|
||||
void
|
||||
intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
|
||||
@ -1501,7 +1519,8 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
|
||||
struct intel_connector *intel_connector);
|
||||
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state);
|
||||
void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable);
|
||||
|
||||
|
||||
@ -1722,6 +1741,21 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
|
||||
void skl_wm_get_hw_state(struct drm_device *dev);
|
||||
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
|
||||
struct skl_ddb_allocation *ddb /* out */);
|
||||
bool skl_can_enable_sagv(struct drm_atomic_state *state);
|
||||
int skl_enable_sagv(struct drm_i915_private *dev_priv);
|
||||
int skl_disable_sagv(struct drm_i915_private *dev_priv);
|
||||
bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
|
||||
const struct skl_ddb_allocation *new,
|
||||
enum pipe pipe);
|
||||
bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
|
||||
const struct skl_ddb_allocation *old,
|
||||
const struct skl_ddb_allocation *new,
|
||||
enum pipe pipe);
|
||||
void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
|
||||
const struct skl_wm_values *wm);
|
||||
void skl_write_plane_wm(struct intel_crtc *intel_crtc,
|
||||
const struct skl_wm_values *wm,
|
||||
int plane);
|
||||
uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
|
||||
bool ilk_disable_lp_wm(struct drm_device *dev);
|
||||
int sanitize_rc6_option(struct drm_i915_private *dev_priv, int enable_rc6);
|
||||
|
@ -312,7 +312,8 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi)
|
||||
}
|
||||
|
||||
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
|
||||
@ -533,14 +534,15 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
|
||||
intel_panel_enable_backlight(intel_dsi->attached_connector);
|
||||
}
|
||||
|
||||
static void intel_dsi_prepare(struct intel_encoder *intel_encoder);
|
||||
static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config);
|
||||
|
||||
static void intel_dsi_pre_enable(struct intel_encoder *encoder)
|
||||
static void intel_dsi_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
enum port port;
|
||||
|
||||
DRM_DEBUG_KMS("\n");
|
||||
@ -550,9 +552,9 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
|
||||
* lock. It needs to be fully powered down to fix it.
|
||||
*/
|
||||
intel_disable_dsi_pll(encoder);
|
||||
intel_enable_dsi_pll(encoder, crtc->config);
|
||||
intel_enable_dsi_pll(encoder, pipe_config);
|
||||
|
||||
intel_dsi_prepare(encoder);
|
||||
intel_dsi_prepare(encoder, pipe_config);
|
||||
|
||||
/* Panel Enable over CRC PMIC */
|
||||
if (intel_dsi->gpio_panel)
|
||||
@ -582,7 +584,9 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
|
||||
intel_dsi_enable(encoder);
|
||||
}
|
||||
|
||||
static void intel_dsi_enable_nop(struct intel_encoder *encoder)
|
||||
static void intel_dsi_enable_nop(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
DRM_DEBUG_KMS("\n");
|
||||
|
||||
@ -592,7 +596,9 @@ static void intel_dsi_enable_nop(struct intel_encoder *encoder)
|
||||
*/
|
||||
}
|
||||
|
||||
static void intel_dsi_pre_disable(struct intel_encoder *encoder)
|
||||
static void intel_dsi_pre_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
|
||||
enum port port;
|
||||
@ -694,7 +700,9 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
|
||||
intel_disable_dsi_pll(encoder);
|
||||
}
|
||||
|
||||
static void intel_dsi_post_disable(struct intel_encoder *encoder)
|
||||
static void intel_dsi_post_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
|
||||
@ -819,6 +827,7 @@ static void bxt_dsi_get_pipe_config(struct intel_encoder *encoder,
|
||||
u16 crtc_htotal_sw, crtc_hsync_start_sw, crtc_hsync_end_sw,
|
||||
crtc_hblank_start_sw, crtc_hblank_end_sw;
|
||||
|
||||
/* FIXME: hw readout should not depend on SW state */
|
||||
intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
adjusted_mode_sw = &intel_crtc->config->base.adjusted_mode;
|
||||
|
||||
@ -1104,14 +1113,15 @@ static u32 pixel_format_to_reg(enum mipi_dsi_pixel_format fmt)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
|
||||
static void intel_dsi_prepare(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_encoder->base;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
|
||||
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
|
||||
const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
enum port port;
|
||||
unsigned int bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format);
|
||||
u32 val, tmp;
|
||||
@ -1348,7 +1358,7 @@ static int intel_dsi_set_property(struct drm_connector *connector,
|
||||
intel_connector->panel.fitting_mode = val;
|
||||
}
|
||||
|
||||
crtc = intel_attached_encoder(connector)->base.crtc;
|
||||
crtc = connector->state->crtc;
|
||||
if (crtc && crtc->state->enable) {
|
||||
/*
|
||||
* If the CRTC is enabled, the display will be changed
|
||||
|
@ -174,7 +174,9 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
|
||||
pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
|
||||
}
|
||||
|
||||
static void intel_disable_dvo(struct intel_encoder *encoder)
|
||||
static void intel_disable_dvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
|
||||
@ -186,17 +188,18 @@ static void intel_disable_dvo(struct intel_encoder *encoder)
|
||||
I915_READ(dvo_reg);
|
||||
}
|
||||
|
||||
static void intel_enable_dvo(struct intel_encoder *encoder)
|
||||
static void intel_enable_dvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg;
|
||||
u32 temp = I915_READ(dvo_reg);
|
||||
|
||||
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
|
||||
&crtc->config->base.mode,
|
||||
&crtc->config->base.adjusted_mode);
|
||||
&pipe_config->base.mode,
|
||||
&pipe_config->base.adjusted_mode);
|
||||
|
||||
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
|
||||
I915_READ(dvo_reg);
|
||||
@ -235,7 +238,8 @@ intel_dvo_mode_valid(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
|
||||
const struct drm_display_mode *fixed_mode =
|
||||
@ -253,12 +257,13 @@ static bool intel_dvo_compute_config(struct intel_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_dvo_pre_enable(struct intel_encoder *encoder)
|
||||
static void intel_dvo_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
|
||||
int pipe = crtc->pipe;
|
||||
u32 dvo_val;
|
||||
@ -554,7 +559,6 @@ void intel_dvo_init(struct drm_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
drm_encoder_cleanup(&intel_encoder->base);
|
||||
kfree(intel_dvo);
|
||||
kfree(intel_connector);
|
||||
}
|
||||
|
@ -211,6 +211,8 @@ void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
|
||||
{
|
||||
memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
|
||||
clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
|
||||
if (intel_engine_has_waiter(engine))
|
||||
i915_queue_hangcheck(engine->i915);
|
||||
}
|
||||
|
||||
static void intel_engine_init_requests(struct intel_engine_cs *engine)
|
||||
@ -230,7 +232,6 @@ static void intel_engine_init_requests(struct intel_engine_cs *engine)
|
||||
*/
|
||||
void intel_engine_setup_common(struct intel_engine_cs *engine)
|
||||
{
|
||||
INIT_LIST_HEAD(&engine->buffers);
|
||||
INIT_LIST_HEAD(&engine->execlist_queue);
|
||||
spin_lock_init(&engine->execlist_lock);
|
||||
|
||||
@ -306,6 +307,18 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_engine_reset_irq(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
if (intel_engine_has_waiter(engine))
|
||||
engine->irq_enable(engine);
|
||||
else
|
||||
engine->irq_disable(engine);
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_engines_cleanup_common - cleans up the engine state created by
|
||||
* the common initiailizers.
|
||||
|
@ -799,10 +799,8 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
|
||||
*/
|
||||
if (cache->fb.tiling_mode != I915_TILING_X ||
|
||||
cache->fb.fence_reg == I915_FENCE_REG_NONE) {
|
||||
if (INTEL_GEN(dev_priv) < 5) {
|
||||
fbc->no_fbc_reason = "framebuffer not tiled or fenced";
|
||||
return false;
|
||||
}
|
||||
fbc->no_fbc_reason = "framebuffer not tiled or fenced";
|
||||
return false;
|
||||
}
|
||||
if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) &&
|
||||
cache->plane.rotation != DRM_ROTATE_0) {
|
||||
|
@ -183,6 +183,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
||||
struct intel_framebuffer *intel_fb = ifbdev->fb;
|
||||
struct drm_device *dev = helper->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct i915_ggtt *ggtt = &dev_priv->ggtt;
|
||||
struct fb_info *info;
|
||||
struct drm_framebuffer *fb;
|
||||
@ -280,7 +281,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
|
||||
ifbdev->vma = vma;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
vga_switcheroo_client_fb_set(dev->pdev, info);
|
||||
vga_switcheroo_client_fb_set(pdev, info);
|
||||
return 0;
|
||||
|
||||
out_destroy_fbi:
|
||||
|
@ -78,9 +78,11 @@ struct i915_guc_client {
|
||||
uint16_t doorbell_id;
|
||||
uint16_t padding[3]; /* Maintain alignment */
|
||||
|
||||
spinlock_t wq_lock;
|
||||
uint32_t wq_offset;
|
||||
uint32_t wq_size;
|
||||
uint32_t wq_tail;
|
||||
uint32_t wq_rsvd;
|
||||
uint32_t no_wq_space;
|
||||
uint32_t b_fail;
|
||||
int retcode;
|
||||
@ -157,7 +159,7 @@ extern int intel_guc_resume(struct drm_device *dev);
|
||||
/* i915_guc_submission.c */
|
||||
int i915_guc_submission_init(struct drm_i915_private *dev_priv);
|
||||
int i915_guc_submission_enable(struct drm_i915_private *dev_priv);
|
||||
int i915_guc_wq_check_space(struct drm_i915_gem_request *rq);
|
||||
int i915_guc_wq_reserve(struct drm_i915_gem_request *rq);
|
||||
void i915_guc_submission_disable(struct drm_i915_private *dev_priv);
|
||||
void i915_guc_submission_fini(struct drm_i915_private *dev_priv);
|
||||
|
||||
|
@ -97,7 +97,7 @@ const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
|
||||
}
|
||||
};
|
||||
|
||||
static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
|
||||
static void guc_interrupts_release(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
int irqs;
|
||||
@ -114,7 +114,7 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
|
||||
I915_WRITE(GUC_WD_VECS_IER, 0);
|
||||
}
|
||||
|
||||
static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
|
||||
static void guc_interrupts_capture(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
int irqs;
|
||||
@ -134,13 +134,28 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
|
||||
I915_WRITE(GUC_WD_VECS_IER, ~irqs);
|
||||
|
||||
/*
|
||||
* If GuC has routed PM interrupts to itself, don't keep it.
|
||||
* and keep other interrupts those are unmasked by GuC.
|
||||
*/
|
||||
* 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_intr_keep' 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_intr_keep so that it's left enabled for the GuC.
|
||||
*
|
||||
* OTOH the REDIRECT_TO_GUC bit is initially SET in pm_intr_keep
|
||||
* (so interrupts go to the DISPLAY unit at first); but here we
|
||||
* need to CLEAR that bit, which will result in the register bit
|
||||
* being left SET!
|
||||
*/
|
||||
tmp = I915_READ(GEN6_PMINTRMSK);
|
||||
if (tmp & GEN8_PMINTR_REDIRECT_TO_NON_DISP) {
|
||||
dev_priv->rps.pm_intr_keep |= ~(tmp & ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
|
||||
dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
|
||||
if (tmp & GEN8_PMINTR_REDIRECT_TO_GUC) {
|
||||
dev_priv->rps.pm_intr_keep |= ~tmp;
|
||||
dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_GUC;
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,17 +167,24 @@ static u32 get_gttype(struct drm_i915_private *dev_priv)
|
||||
|
||||
static u32 get_core_family(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
switch (INTEL_INFO(dev_priv)->gen) {
|
||||
u32 gen = INTEL_GEN(dev_priv);
|
||||
|
||||
switch (gen) {
|
||||
case 9:
|
||||
return GFXCORE_FAMILY_GEN9;
|
||||
|
||||
default:
|
||||
DRM_ERROR("GUC: unsupported core family\n");
|
||||
WARN(1, "GEN%d does not support GuC operation!\n", gen);
|
||||
return GFXCORE_FAMILY_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_guc_init_params(struct drm_i915_private *dev_priv)
|
||||
/*
|
||||
* Initialise the GuC parameter block before starting the firmware
|
||||
* transfer. These parameters are read by the firmware on startup
|
||||
* and cannot be changed thereafter.
|
||||
*/
|
||||
static void guc_params_init(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_guc *guc = &dev_priv->guc;
|
||||
u32 params[GUC_CTL_MAX_DWORDS];
|
||||
@ -375,11 +397,11 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
|
||||
I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE |
|
||||
I915_READ(GEN7_MISCCPCTL)));
|
||||
|
||||
/* allows for 5us before GT can go to RC6 */
|
||||
/* allows for 5us (in 10ns units) before GT can go to RC6 */
|
||||
I915_WRITE(GUC_ARAT_C6DIS, 0x1FF);
|
||||
}
|
||||
|
||||
set_guc_init_params(dev_priv);
|
||||
guc_params_init(dev_priv);
|
||||
|
||||
ret = guc_ucode_xfer_dma(dev_priv, vma);
|
||||
|
||||
@ -394,7 +416,7 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int i915_reset_guc(struct drm_i915_private *dev_priv)
|
||||
static int guc_hw_reset(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret;
|
||||
u32 guc_status;
|
||||
@ -447,7 +469,7 @@ int intel_guc_setup(struct drm_device *dev)
|
||||
goto fail;
|
||||
} else if (*fw_path == '\0') {
|
||||
/* Device has a GuC but we don't know what f/w to load? */
|
||||
DRM_INFO("No GuC firmware known for this platform\n");
|
||||
WARN(1, "No GuC firmware known for this platform!\n");
|
||||
err = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
@ -461,7 +483,7 @@ int intel_guc_setup(struct drm_device *dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
direct_interrupts_to_host(dev_priv);
|
||||
guc_interrupts_release(dev_priv);
|
||||
|
||||
guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
|
||||
|
||||
@ -484,11 +506,9 @@ int intel_guc_setup(struct drm_device *dev)
|
||||
* Always reset the GuC just before (re)loading, so
|
||||
* that the state and timing are fairly predictable
|
||||
*/
|
||||
err = i915_reset_guc(dev_priv);
|
||||
if (err) {
|
||||
DRM_ERROR("GuC reset failed: %d\n", err);
|
||||
err = guc_hw_reset(dev_priv);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = guc_ucode_xfer(dev_priv);
|
||||
if (!err)
|
||||
@ -511,7 +531,7 @@ int intel_guc_setup(struct drm_device *dev)
|
||||
err = i915_guc_submission_enable(dev_priv);
|
||||
if (err)
|
||||
goto fail;
|
||||
direct_interrupts_to_guc(dev_priv);
|
||||
guc_interrupts_capture(dev_priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -520,7 +540,7 @@ fail:
|
||||
if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING)
|
||||
guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL;
|
||||
|
||||
direct_interrupts_to_host(dev_priv);
|
||||
guc_interrupts_release(dev_priv);
|
||||
i915_guc_submission_disable(dev_priv);
|
||||
i915_guc_submission_fini(dev_priv);
|
||||
|
||||
@ -546,15 +566,15 @@ fail:
|
||||
else if (err == 0)
|
||||
DRM_INFO("GuC firmware load skipped\n");
|
||||
else if (ret != -EIO)
|
||||
DRM_INFO("GuC firmware load failed: %d\n", err);
|
||||
DRM_NOTE("GuC firmware load failed: %d\n", err);
|
||||
else
|
||||
DRM_ERROR("GuC firmware load failed: %d\n", err);
|
||||
DRM_WARN("GuC firmware load failed: %d\n", err);
|
||||
|
||||
if (i915.enable_guc_submission) {
|
||||
if (fw_path == NULL)
|
||||
DRM_INFO("GuC submission without firmware not supported\n");
|
||||
if (ret == 0)
|
||||
DRM_INFO("Falling back from GuC submission to execlist mode\n");
|
||||
DRM_NOTE("Falling back from GuC submission to execlist mode\n");
|
||||
else
|
||||
DRM_ERROR("GuC init failed: %d\n", ret);
|
||||
}
|
||||
@ -565,6 +585,7 @@ fail:
|
||||
|
||||
static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
{
|
||||
struct pci_dev *pdev = dev->pdev;
|
||||
struct drm_i915_gem_object *obj;
|
||||
const struct firmware *fw;
|
||||
struct guc_css_header *css;
|
||||
@ -574,7 +595,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n",
|
||||
intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
|
||||
|
||||
err = request_firmware(&fw, guc_fw->guc_fw_path, &dev->pdev->dev);
|
||||
err = request_firmware(&fw, guc_fw->guc_fw_path, &pdev->dev);
|
||||
if (err)
|
||||
goto fail;
|
||||
if (!fw)
|
||||
@ -585,7 +606,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
|
||||
/* Check the size of the blob before examining buffer contents */
|
||||
if (fw->size < sizeof(struct guc_css_header)) {
|
||||
DRM_ERROR("Firmware header is missing\n");
|
||||
DRM_NOTE("Firmware header is missing\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -597,7 +618,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
css->key_size_dw - css->exponent_size_dw) * sizeof(u32);
|
||||
|
||||
if (guc_fw->header_size != sizeof(struct guc_css_header)) {
|
||||
DRM_ERROR("CSS header definition mismatch\n");
|
||||
DRM_NOTE("CSS header definition mismatch\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -607,7 +628,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
|
||||
/* now RSA */
|
||||
if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) {
|
||||
DRM_ERROR("RSA key size is bad\n");
|
||||
DRM_NOTE("RSA key size is bad\n");
|
||||
goto fail;
|
||||
}
|
||||
guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size;
|
||||
@ -616,14 +637,14 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
/* At least, it should have header, uCode and RSA. Size of all three. */
|
||||
size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size;
|
||||
if (fw->size < size) {
|
||||
DRM_ERROR("Missing firmware components\n");
|
||||
DRM_NOTE("Missing firmware components\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Header and uCode will be loaded to WOPCM. Size of the two. */
|
||||
size = guc_fw->header_size + guc_fw->ucode_size;
|
||||
if (size > guc_wopcm_size(to_i915(dev))) {
|
||||
DRM_ERROR("Firmware is too large to fit in WOPCM\n");
|
||||
DRM_NOTE("Firmware is too large to fit in WOPCM\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -638,7 +659,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
|
||||
if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted ||
|
||||
guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) {
|
||||
DRM_ERROR("GuC firmware version %d.%d, required %d.%d\n",
|
||||
DRM_NOTE("GuC firmware version %d.%d, required %d.%d\n",
|
||||
guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
|
||||
guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
|
||||
err = -ENOEXEC;
|
||||
@ -668,10 +689,10 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
|
||||
return;
|
||||
|
||||
fail:
|
||||
DRM_WARN("Failed to fetch valid GuC firmware from %s (error %d)\n",
|
||||
guc_fw->guc_fw_path, err);
|
||||
DRM_DEBUG_DRIVER("GuC fw fetch status FAIL; err %d, fw %p, obj %p\n",
|
||||
err, fw, guc_fw->guc_fw_obj);
|
||||
DRM_ERROR("Failed to fetch GuC firmware from %s (error %d)\n",
|
||||
guc_fw->guc_fw_path, err);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
obj = guc_fw->guc_fw_obj;
|
||||
@ -752,7 +773,7 @@ void intel_guc_fini(struct drm_device *dev)
|
||||
struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
direct_interrupts_to_host(dev_priv);
|
||||
guc_interrupts_release(dev_priv);
|
||||
i915_guc_submission_disable(dev_priv);
|
||||
i915_guc_submission_fini(dev_priv);
|
||||
|
||||
|
@ -985,7 +985,9 @@ static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
|
||||
intel_audio_codec_enable(encoder);
|
||||
}
|
||||
|
||||
static void g4x_enable_hdmi(struct intel_encoder *encoder)
|
||||
static void g4x_enable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1006,7 +1008,9 @@ static void g4x_enable_hdmi(struct intel_encoder *encoder)
|
||||
intel_enable_hdmi_audio(encoder);
|
||||
}
|
||||
|
||||
static void ibx_enable_hdmi(struct intel_encoder *encoder)
|
||||
static void ibx_enable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1055,7 +1059,9 @@ static void ibx_enable_hdmi(struct intel_encoder *encoder)
|
||||
intel_enable_hdmi_audio(encoder);
|
||||
}
|
||||
|
||||
static void cpt_enable_hdmi(struct intel_encoder *encoder)
|
||||
static void cpt_enable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1108,11 +1114,15 @@ static void cpt_enable_hdmi(struct intel_encoder *encoder)
|
||||
intel_enable_hdmi_audio(encoder);
|
||||
}
|
||||
|
||||
static void vlv_enable_hdmi(struct intel_encoder *encoder)
|
||||
static void vlv_enable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
}
|
||||
|
||||
static void intel_disable_hdmi(struct intel_encoder *encoder)
|
||||
static void intel_disable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1164,17 +1174,21 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
|
||||
intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
|
||||
}
|
||||
|
||||
static void g4x_disable_hdmi(struct intel_encoder *encoder)
|
||||
static void g4x_disable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
|
||||
if (crtc->config->has_audio)
|
||||
intel_audio_codec_disable(encoder);
|
||||
|
||||
intel_disable_hdmi(encoder);
|
||||
intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static void pch_disable_hdmi(struct intel_encoder *encoder)
|
||||
static void pch_disable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
|
||||
@ -1182,9 +1196,11 @@ static void pch_disable_hdmi(struct intel_encoder *encoder)
|
||||
intel_audio_codec_disable(encoder);
|
||||
}
|
||||
|
||||
static void pch_post_disable_hdmi(struct intel_encoder *encoder)
|
||||
static void pch_post_disable_hdmi(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_disable_hdmi(encoder);
|
||||
intel_disable_hdmi(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv)
|
||||
@ -1285,7 +1301,8 @@ static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
|
||||
}
|
||||
|
||||
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
@ -1422,24 +1439,22 @@ intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_hdmi_set_edid(struct drm_connector *connector, bool force)
|
||||
intel_hdmi_set_edid(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->dev);
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct edid *edid = NULL;
|
||||
struct edid *edid;
|
||||
bool connected = false;
|
||||
|
||||
if (force) {
|
||||
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
edid = drm_get_edid(connector,
|
||||
intel_gmbus_get_adapter(dev_priv,
|
||||
intel_hdmi->ddc_bus));
|
||||
|
||||
intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
|
||||
intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
|
||||
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
}
|
||||
intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
|
||||
to_intel_connector(connector)->detect_edid = edid;
|
||||
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
@ -1465,37 +1480,16 @@ static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
enum drm_connector_status status;
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
struct drm_i915_private *dev_priv = to_i915(connector->dev);
|
||||
bool live_status = false;
|
||||
unsigned int try;
|
||||
|
||||
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
|
||||
connector->base.id, connector->name);
|
||||
|
||||
intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
|
||||
|
||||
for (try = 0; !live_status && try < 9; try++) {
|
||||
if (try)
|
||||
msleep(10);
|
||||
live_status = intel_digital_port_connected(dev_priv,
|
||||
hdmi_to_dig_port(intel_hdmi));
|
||||
}
|
||||
|
||||
if (!live_status) {
|
||||
DRM_DEBUG_KMS("HDMI live status down\n");
|
||||
/*
|
||||
* Live status register is not reliable on all intel platforms.
|
||||
* So consider live_status only for certain platforms, for
|
||||
* others, read EDID to determine presence of sink.
|
||||
*/
|
||||
if (INTEL_INFO(dev_priv)->gen < 7 || IS_IVYBRIDGE(dev_priv))
|
||||
live_status = true;
|
||||
}
|
||||
|
||||
intel_hdmi_unset_edid(connector);
|
||||
|
||||
if (intel_hdmi_set_edid(connector, live_status)) {
|
||||
if (intel_hdmi_set_edid(connector)) {
|
||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||
|
||||
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
|
||||
@ -1521,7 +1515,7 @@ intel_hdmi_force(struct drm_connector *connector)
|
||||
if (connector->status != connector_status_connected)
|
||||
return;
|
||||
|
||||
intel_hdmi_set_edid(connector, true);
|
||||
intel_hdmi_set_edid(connector);
|
||||
hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;
|
||||
}
|
||||
|
||||
@ -1638,7 +1632,9 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
static void intel_hdmi_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
|
||||
@ -1651,7 +1647,9 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
adjusted_mode);
|
||||
}
|
||||
|
||||
static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
static void vlv_hdmi_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct intel_hdmi *intel_hdmi = &dport->hdmi;
|
||||
@ -1671,37 +1669,47 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
intel_crtc->config->has_hdmi_sink,
|
||||
adjusted_mode);
|
||||
|
||||
g4x_enable_hdmi(encoder);
|
||||
g4x_enable_hdmi(encoder, pipe_config, conn_state);
|
||||
|
||||
vlv_wait_port_ready(dev_priv, dport, 0x0);
|
||||
}
|
||||
|
||||
static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
|
||||
static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
intel_hdmi_prepare(encoder);
|
||||
|
||||
vlv_phy_pre_pll_enable(encoder);
|
||||
}
|
||||
|
||||
static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
|
||||
static void chv_hdmi_pre_pll_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
intel_hdmi_prepare(encoder);
|
||||
|
||||
chv_phy_pre_pll_enable(encoder);
|
||||
}
|
||||
|
||||
static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder)
|
||||
static void chv_hdmi_post_pll_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
chv_phy_post_pll_disable(encoder);
|
||||
}
|
||||
|
||||
static void vlv_hdmi_post_disable(struct intel_encoder *encoder)
|
||||
static void vlv_hdmi_post_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
/* Reset lanes to avoid HDMI flicker (VLV w/a) */
|
||||
vlv_phy_reset_lanes(encoder);
|
||||
}
|
||||
|
||||
static void chv_hdmi_post_disable(struct intel_encoder *encoder)
|
||||
static void chv_hdmi_post_disable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -1714,7 +1722,9 @@ static void chv_hdmi_post_disable(struct intel_encoder *encoder)
|
||||
mutex_unlock(&dev_priv->sb_lock);
|
||||
}
|
||||
|
||||
static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
static void chv_hdmi_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
|
||||
struct intel_hdmi *intel_hdmi = &dport->hdmi;
|
||||
@ -1734,7 +1744,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
|
||||
intel_crtc->config->has_hdmi_sink,
|
||||
adjusted_mode);
|
||||
|
||||
g4x_enable_hdmi(encoder);
|
||||
g4x_enable_hdmi(encoder, pipe_config, conn_state);
|
||||
|
||||
vlv_wait_port_ready(dev_priv, dport, 0x0);
|
||||
|
||||
|
@ -255,67 +255,59 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin)
|
||||
algo->data = bus;
|
||||
}
|
||||
|
||||
static int
|
||||
gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
|
||||
u32 gmbus2_status,
|
||||
u32 gmbus4_irq_en)
|
||||
static int gmbus_wait(struct drm_i915_private *dev_priv, u32 status, u32 irq_en)
|
||||
{
|
||||
int i;
|
||||
u32 gmbus2 = 0;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
if (!HAS_GMBUS_IRQ(dev_priv))
|
||||
gmbus4_irq_en = 0;
|
||||
u32 gmbus2;
|
||||
int ret;
|
||||
|
||||
/* Important: The hw handles only the first bit, so set only one! Since
|
||||
* we also need to check for NAKs besides the hw ready/idle signal, we
|
||||
* need to wake up periodically and check that ourselves. */
|
||||
I915_WRITE(GMBUS4, gmbus4_irq_en);
|
||||
* need to wake up periodically and check that ourselves.
|
||||
*/
|
||||
if (!HAS_GMBUS_IRQ(dev_priv))
|
||||
irq_en = 0;
|
||||
|
||||
for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
|
||||
prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
|
||||
I915_WRITE_FW(GMBUS4, irq_en);
|
||||
|
||||
gmbus2 = I915_READ_NOTRACE(GMBUS2);
|
||||
if (gmbus2 & (GMBUS_SATOER | gmbus2_status))
|
||||
break;
|
||||
status |= GMBUS_SATOER;
|
||||
ret = wait_for_us((gmbus2 = I915_READ_FW(GMBUS2)) & status, 2);
|
||||
if (ret)
|
||||
ret = wait_for((gmbus2 = I915_READ_FW(GMBUS2)) & status, 50);
|
||||
|
||||
schedule_timeout(1);
|
||||
}
|
||||
finish_wait(&dev_priv->gmbus_wait_queue, &wait);
|
||||
|
||||
I915_WRITE(GMBUS4, 0);
|
||||
I915_WRITE_FW(GMBUS4, 0);
|
||||
remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
|
||||
|
||||
if (gmbus2 & GMBUS_SATOER)
|
||||
return -ENXIO;
|
||||
if (gmbus2 & gmbus2_status)
|
||||
return 0;
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
gmbus_wait_idle(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
u32 irq_enable;
|
||||
int ret;
|
||||
|
||||
if (!HAS_GMBUS_IRQ(dev_priv))
|
||||
return intel_wait_for_register(dev_priv,
|
||||
GMBUS2, GMBUS_ACTIVE, 0,
|
||||
10);
|
||||
|
||||
/* Important: The hw handles only the first bit, so set only one! */
|
||||
I915_WRITE(GMBUS4, GMBUS_IDLE_EN);
|
||||
irq_enable = 0;
|
||||
if (HAS_GMBUS_IRQ(dev_priv))
|
||||
irq_enable = GMBUS_IDLE_EN;
|
||||
|
||||
ret = wait_event_timeout(dev_priv->gmbus_wait_queue,
|
||||
(I915_READ_NOTRACE(GMBUS2) & GMBUS_ACTIVE) == 0,
|
||||
msecs_to_jiffies_timeout(10));
|
||||
add_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
|
||||
I915_WRITE_FW(GMBUS4, irq_enable);
|
||||
|
||||
I915_WRITE(GMBUS4, 0);
|
||||
ret = intel_wait_for_register_fw(dev_priv,
|
||||
GMBUS2, GMBUS_ACTIVE, 0,
|
||||
10);
|
||||
|
||||
if (ret)
|
||||
return 0;
|
||||
else
|
||||
return -ETIMEDOUT;
|
||||
I915_WRITE_FW(GMBUS4, 0);
|
||||
remove_wait_queue(&dev_priv->gmbus_wait_queue, &wait);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -323,22 +315,21 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
|
||||
unsigned short addr, u8 *buf, unsigned int len,
|
||||
u32 gmbus1_index)
|
||||
{
|
||||
I915_WRITE(GMBUS1,
|
||||
gmbus1_index |
|
||||
GMBUS_CYCLE_WAIT |
|
||||
(len << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_READ | GMBUS_SW_RDY);
|
||||
I915_WRITE_FW(GMBUS1,
|
||||
gmbus1_index |
|
||||
GMBUS_CYCLE_WAIT |
|
||||
(len << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_READ | GMBUS_SW_RDY);
|
||||
while (len) {
|
||||
int ret;
|
||||
u32 val, loop = 0;
|
||||
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
|
||||
GMBUS_HW_RDY_EN);
|
||||
ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = I915_READ(GMBUS3);
|
||||
val = I915_READ_FW(GMBUS3);
|
||||
do {
|
||||
*buf++ = val & 0xff;
|
||||
val >>= 8;
|
||||
@ -385,12 +376,12 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
|
||||
len -= 1;
|
||||
}
|
||||
|
||||
I915_WRITE(GMBUS3, val);
|
||||
I915_WRITE(GMBUS1,
|
||||
GMBUS_CYCLE_WAIT |
|
||||
(chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
|
||||
I915_WRITE_FW(GMBUS3, val);
|
||||
I915_WRITE_FW(GMBUS1,
|
||||
GMBUS_CYCLE_WAIT |
|
||||
(chunk_size << GMBUS_BYTE_COUNT_SHIFT) |
|
||||
(addr << GMBUS_SLAVE_ADDR_SHIFT) |
|
||||
GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
|
||||
while (len) {
|
||||
int ret;
|
||||
|
||||
@ -399,10 +390,9 @@ gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv,
|
||||
val |= *buf++ << (8 * loop);
|
||||
} while (--len && ++loop < 4);
|
||||
|
||||
I915_WRITE(GMBUS3, val);
|
||||
I915_WRITE_FW(GMBUS3, val);
|
||||
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY,
|
||||
GMBUS_HW_RDY_EN);
|
||||
ret = gmbus_wait(dev_priv, GMBUS_HW_RDY, GMBUS_HW_RDY_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -460,13 +450,13 @@ gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
|
||||
|
||||
/* GMBUS5 holds 16-bit index */
|
||||
if (gmbus5)
|
||||
I915_WRITE(GMBUS5, gmbus5);
|
||||
I915_WRITE_FW(GMBUS5, gmbus5);
|
||||
|
||||
ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
|
||||
|
||||
/* Clear GMBUS5 after each index transfer */
|
||||
if (gmbus5)
|
||||
I915_WRITE(GMBUS5, 0);
|
||||
I915_WRITE_FW(GMBUS5, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -478,11 +468,15 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
|
||||
struct intel_gmbus,
|
||||
adapter);
|
||||
struct drm_i915_private *dev_priv = bus->dev_priv;
|
||||
const unsigned int fw =
|
||||
intel_uncore_forcewake_for_reg(dev_priv, GMBUS0,
|
||||
FW_REG_READ | FW_REG_WRITE);
|
||||
int i = 0, inc, try = 0;
|
||||
int ret = 0;
|
||||
|
||||
intel_uncore_forcewake_get(dev_priv, fw);
|
||||
retry:
|
||||
I915_WRITE(GMBUS0, bus->reg0);
|
||||
I915_WRITE_FW(GMBUS0, bus->reg0);
|
||||
|
||||
for (; i < num; i += inc) {
|
||||
inc = 1;
|
||||
@ -496,8 +490,8 @@ retry:
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE,
|
||||
GMBUS_HW_WAIT_EN);
|
||||
ret = gmbus_wait(dev_priv,
|
||||
GMBUS_HW_WAIT_PHASE, GMBUS_HW_WAIT_EN);
|
||||
if (ret == -ETIMEDOUT)
|
||||
goto timeout;
|
||||
else if (ret)
|
||||
@ -508,7 +502,7 @@ retry:
|
||||
* a STOP on the very first cycle. To simplify the code we
|
||||
* unconditionally generate the STOP condition with an additional gmbus
|
||||
* cycle. */
|
||||
I915_WRITE(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
|
||||
I915_WRITE_FW(GMBUS1, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
|
||||
|
||||
/* Mark the GMBUS interface as disabled after waiting for idle.
|
||||
* We will re-enable it at the start of the next xfer,
|
||||
@ -519,7 +513,7 @@ retry:
|
||||
adapter->name);
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
I915_WRITE(GMBUS0, 0);
|
||||
I915_WRITE_FW(GMBUS0, 0);
|
||||
ret = ret ?: i;
|
||||
goto out;
|
||||
|
||||
@ -548,9 +542,9 @@ clear_err:
|
||||
* of resetting the GMBUS controller and so clearing the
|
||||
* BUS_ERROR raised by the slave's NAK.
|
||||
*/
|
||||
I915_WRITE(GMBUS1, GMBUS_SW_CLR_INT);
|
||||
I915_WRITE(GMBUS1, 0);
|
||||
I915_WRITE(GMBUS0, 0);
|
||||
I915_WRITE_FW(GMBUS1, GMBUS_SW_CLR_INT);
|
||||
I915_WRITE_FW(GMBUS1, 0);
|
||||
I915_WRITE_FW(GMBUS0, 0);
|
||||
|
||||
DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
|
||||
adapter->name, msgs[i].addr,
|
||||
@ -573,7 +567,7 @@ clear_err:
|
||||
timeout:
|
||||
DRM_DEBUG_KMS("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
|
||||
bus->adapter.name, bus->reg0 & 0xff);
|
||||
I915_WRITE(GMBUS0, 0);
|
||||
I915_WRITE_FW(GMBUS0, 0);
|
||||
|
||||
/*
|
||||
* Hardware may not support GMBUS over these pins? Try GPIO bitbanging
|
||||
@ -582,6 +576,7 @@ timeout:
|
||||
ret = -EAGAIN;
|
||||
|
||||
out:
|
||||
intel_uncore_forcewake_put(dev_priv, fw);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -633,6 +628,7 @@ static const struct i2c_algorithm gmbus_algorithm = {
|
||||
int intel_setup_gmbus(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct intel_gmbus *bus;
|
||||
unsigned int pin;
|
||||
int ret;
|
||||
@ -663,7 +659,7 @@ int intel_setup_gmbus(struct drm_device *dev)
|
||||
"i915 gmbus %s",
|
||||
get_gmbus_pin(dev_priv, pin)->name);
|
||||
|
||||
bus->adapter.dev.parent = &dev->pdev->dev;
|
||||
bus->adapter.dev.parent = &pdev->dev;
|
||||
bus->dev_priv = dev_priv;
|
||||
|
||||
bus->adapter.algo = &gmbus_algorithm;
|
||||
|
@ -156,6 +156,11 @@
|
||||
#define GEN8_CTX_STATUS_COMPLETE (1 << 4)
|
||||
#define GEN8_CTX_STATUS_LITE_RESTORE (1 << 15)
|
||||
|
||||
#define GEN8_CTX_STATUS_COMPLETED_MASK \
|
||||
(GEN8_CTX_STATUS_ACTIVE_IDLE | \
|
||||
GEN8_CTX_STATUS_PREEMPTED | \
|
||||
GEN8_CTX_STATUS_ELEMENT_SWITCH)
|
||||
|
||||
#define CTX_LRI_HEADER_0 0x01
|
||||
#define CTX_CONTEXT_CONTROL 0x02
|
||||
#define CTX_RING_HEAD 0x04
|
||||
@ -263,12 +268,10 @@ logical_ring_init_platform_invariants(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
|
||||
if (IS_GEN8(dev_priv) || IS_GEN9(dev_priv))
|
||||
engine->idle_lite_restore_wa = ~0;
|
||||
|
||||
engine->disable_lite_restore_wa = (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
|
||||
IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) &&
|
||||
(engine->id == VCS || engine->id == VCS2);
|
||||
engine->disable_lite_restore_wa =
|
||||
(IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
|
||||
IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) &&
|
||||
(engine->id == VCS || engine->id == VCS2);
|
||||
|
||||
engine->ctx_desc_template = GEN8_CTX_VALID;
|
||||
if (IS_GEN8(dev_priv))
|
||||
@ -328,85 +331,9 @@ uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx,
|
||||
return ctx->engine[engine->id].lrc_desc;
|
||||
}
|
||||
|
||||
static void execlists_elsp_write(struct drm_i915_gem_request *rq0,
|
||||
struct drm_i915_gem_request *rq1)
|
||||
{
|
||||
|
||||
struct intel_engine_cs *engine = rq0->engine;
|
||||
struct drm_i915_private *dev_priv = rq0->i915;
|
||||
uint64_t desc[2];
|
||||
|
||||
if (rq1) {
|
||||
desc[1] = intel_lr_context_descriptor(rq1->ctx, rq1->engine);
|
||||
rq1->elsp_submitted++;
|
||||
} else {
|
||||
desc[1] = 0;
|
||||
}
|
||||
|
||||
desc[0] = intel_lr_context_descriptor(rq0->ctx, rq0->engine);
|
||||
rq0->elsp_submitted++;
|
||||
|
||||
/* You must always write both descriptors in the order below. */
|
||||
I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[1]));
|
||||
I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[1]));
|
||||
|
||||
I915_WRITE_FW(RING_ELSP(engine), upper_32_bits(desc[0]));
|
||||
/* The context is automatically loaded after the following */
|
||||
I915_WRITE_FW(RING_ELSP(engine), lower_32_bits(desc[0]));
|
||||
|
||||
/* ELSP is a wo register, use another nearby reg for posting */
|
||||
POSTING_READ_FW(RING_EXECLIST_STATUS_LO(engine));
|
||||
}
|
||||
|
||||
static void
|
||||
execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
|
||||
{
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
|
||||
}
|
||||
|
||||
static void execlists_update_context(struct drm_i915_gem_request *rq)
|
||||
{
|
||||
struct intel_engine_cs *engine = rq->engine;
|
||||
struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt;
|
||||
uint32_t *reg_state = rq->ctx->engine[engine->id].lrc_reg_state;
|
||||
|
||||
reg_state[CTX_RING_TAIL+1] = intel_ring_offset(rq->ring, rq->tail);
|
||||
|
||||
/* True 32b PPGTT with dynamic page allocation: update PDP
|
||||
* registers and point the unallocated PDPs to scratch page.
|
||||
* PML4 is allocated during ppgtt init, so this is not needed
|
||||
* in 48-bit mode.
|
||||
*/
|
||||
if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
|
||||
execlists_update_context_pdps(ppgtt, reg_state);
|
||||
}
|
||||
|
||||
static void execlists_elsp_submit_contexts(struct drm_i915_gem_request *rq0,
|
||||
struct drm_i915_gem_request *rq1)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = rq0->i915;
|
||||
unsigned int fw_domains = rq0->engine->fw_domains;
|
||||
|
||||
execlists_update_context(rq0);
|
||||
|
||||
if (rq1)
|
||||
execlists_update_context(rq1);
|
||||
|
||||
spin_lock_irq(&dev_priv->uncore.lock);
|
||||
intel_uncore_forcewake_get__locked(dev_priv, fw_domains);
|
||||
|
||||
execlists_elsp_write(rq0, rq1);
|
||||
|
||||
intel_uncore_forcewake_put__locked(dev_priv, fw_domains);
|
||||
spin_unlock_irq(&dev_priv->uncore.lock);
|
||||
}
|
||||
|
||||
static inline void execlists_context_status_change(
|
||||
struct drm_i915_gem_request *rq,
|
||||
unsigned long status)
|
||||
static inline void
|
||||
execlists_context_status_change(struct drm_i915_gem_request *rq,
|
||||
unsigned long status)
|
||||
{
|
||||
/*
|
||||
* Only used when GVT-g is enabled now. When GVT-g is disabled,
|
||||
@ -418,122 +345,187 @@ static inline void execlists_context_status_change(
|
||||
atomic_notifier_call_chain(&rq->ctx->status_notifier, status, rq);
|
||||
}
|
||||
|
||||
static void execlists_unqueue(struct intel_engine_cs *engine)
|
||||
static void
|
||||
execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
|
||||
{
|
||||
struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
|
||||
struct drm_i915_gem_request *cursor, *tmp;
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 3);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 2);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 1);
|
||||
ASSIGN_CTX_PDP(ppgtt, reg_state, 0);
|
||||
}
|
||||
|
||||
assert_spin_locked(&engine->execlist_lock);
|
||||
static u64 execlists_update_context(struct drm_i915_gem_request *rq)
|
||||
{
|
||||
struct intel_context *ce = &rq->ctx->engine[rq->engine->id];
|
||||
struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt;
|
||||
u32 *reg_state = ce->lrc_reg_state;
|
||||
|
||||
/*
|
||||
* If irqs are not active generate a warning as batches that finish
|
||||
* without the irqs may get lost and a GPU Hang may occur.
|
||||
reg_state[CTX_RING_TAIL+1] = intel_ring_offset(rq->ring, rq->tail);
|
||||
|
||||
/* True 32b PPGTT with dynamic page allocation: update PDP
|
||||
* registers and point the unallocated PDPs to scratch page.
|
||||
* PML4 is allocated during ppgtt init, so this is not needed
|
||||
* in 48-bit mode.
|
||||
*/
|
||||
WARN_ON(!intel_irqs_enabled(engine->i915));
|
||||
if (ppgtt && !USES_FULL_48BIT_PPGTT(ppgtt->base.dev))
|
||||
execlists_update_context_pdps(ppgtt, reg_state);
|
||||
|
||||
/* Try to read in pairs */
|
||||
list_for_each_entry_safe(cursor, tmp, &engine->execlist_queue,
|
||||
execlist_link) {
|
||||
if (!req0) {
|
||||
req0 = cursor;
|
||||
} else if (req0->ctx == cursor->ctx) {
|
||||
/* Same ctx: ignore first request, as second request
|
||||
* will update tail past first request's workload */
|
||||
cursor->elsp_submitted = req0->elsp_submitted;
|
||||
list_del(&req0->execlist_link);
|
||||
i915_gem_request_put(req0);
|
||||
req0 = cursor;
|
||||
} else {
|
||||
if (IS_ENABLED(CONFIG_DRM_I915_GVT)) {
|
||||
/*
|
||||
* req0 (after merged) ctx requires single
|
||||
* submission, stop picking
|
||||
*/
|
||||
if (req0->ctx->execlists_force_single_submission)
|
||||
break;
|
||||
/*
|
||||
* req0 ctx doesn't require single submission,
|
||||
* but next req ctx requires, stop picking
|
||||
*/
|
||||
if (cursor->ctx->execlists_force_single_submission)
|
||||
break;
|
||||
}
|
||||
req1 = cursor;
|
||||
WARN_ON(req1->elsp_submitted);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!req0))
|
||||
return;
|
||||
|
||||
execlists_context_status_change(req0, INTEL_CONTEXT_SCHEDULE_IN);
|
||||
|
||||
if (req1)
|
||||
execlists_context_status_change(req1,
|
||||
INTEL_CONTEXT_SCHEDULE_IN);
|
||||
|
||||
if (req0->elsp_submitted & engine->idle_lite_restore_wa) {
|
||||
/*
|
||||
* WaIdleLiteRestore: make sure we never cause a lite restore
|
||||
* with HEAD==TAIL.
|
||||
*
|
||||
* Apply the wa NOOPS to prevent ring:HEAD == req:TAIL as we
|
||||
* resubmit the request. See gen8_emit_request() for where we
|
||||
* prepare the padding after the end of the request.
|
||||
*/
|
||||
req0->tail += 8;
|
||||
req0->tail &= req0->ring->size - 1;
|
||||
}
|
||||
|
||||
execlists_elsp_submit_contexts(req0, req1);
|
||||
return ce->lrc_desc;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
execlists_check_remove_request(struct intel_engine_cs *engine, u32 ctx_id)
|
||||
{
|
||||
struct drm_i915_gem_request *head_req;
|
||||
|
||||
assert_spin_locked(&engine->execlist_lock);
|
||||
|
||||
head_req = list_first_entry_or_null(&engine->execlist_queue,
|
||||
struct drm_i915_gem_request,
|
||||
execlist_link);
|
||||
|
||||
if (WARN_ON(!head_req || (head_req->ctx_hw_id != ctx_id)))
|
||||
return 0;
|
||||
|
||||
WARN(head_req->elsp_submitted == 0, "Never submitted head request\n");
|
||||
|
||||
if (--head_req->elsp_submitted > 0)
|
||||
return 0;
|
||||
|
||||
execlists_context_status_change(head_req, INTEL_CONTEXT_SCHEDULE_OUT);
|
||||
|
||||
list_del(&head_req->execlist_link);
|
||||
i915_gem_request_put(head_req);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u32
|
||||
get_context_status(struct intel_engine_cs *engine, unsigned int read_pointer,
|
||||
u32 *context_id)
|
||||
static void execlists_submit_ports(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
u32 status;
|
||||
struct execlist_port *port = engine->execlist_port;
|
||||
u32 __iomem *elsp =
|
||||
dev_priv->regs + i915_mmio_reg_offset(RING_ELSP(engine));
|
||||
u64 desc[2];
|
||||
|
||||
read_pointer %= GEN8_CSB_ENTRIES;
|
||||
if (!port[0].count)
|
||||
execlists_context_status_change(port[0].request,
|
||||
INTEL_CONTEXT_SCHEDULE_IN);
|
||||
desc[0] = execlists_update_context(port[0].request);
|
||||
engine->preempt_wa = port[0].count++; /* bdw only? fixed on skl? */
|
||||
|
||||
status = I915_READ_FW(RING_CONTEXT_STATUS_BUF_LO(engine, read_pointer));
|
||||
if (port[1].request) {
|
||||
GEM_BUG_ON(port[1].count);
|
||||
execlists_context_status_change(port[1].request,
|
||||
INTEL_CONTEXT_SCHEDULE_IN);
|
||||
desc[1] = execlists_update_context(port[1].request);
|
||||
port[1].count = 1;
|
||||
} else {
|
||||
desc[1] = 0;
|
||||
}
|
||||
GEM_BUG_ON(desc[0] == desc[1]);
|
||||
|
||||
if (status & GEN8_CTX_STATUS_IDLE_ACTIVE)
|
||||
return 0;
|
||||
/* You must always write both descriptors in the order below. */
|
||||
writel(upper_32_bits(desc[1]), elsp);
|
||||
writel(lower_32_bits(desc[1]), elsp);
|
||||
|
||||
*context_id = I915_READ_FW(RING_CONTEXT_STATUS_BUF_HI(engine,
|
||||
read_pointer));
|
||||
writel(upper_32_bits(desc[0]), elsp);
|
||||
/* The context is automatically loaded after the following */
|
||||
writel(lower_32_bits(desc[0]), elsp);
|
||||
}
|
||||
|
||||
return status;
|
||||
static bool ctx_single_port_submission(const struct i915_gem_context *ctx)
|
||||
{
|
||||
return (IS_ENABLED(CONFIG_DRM_I915_GVT) &&
|
||||
ctx->execlists_force_single_submission);
|
||||
}
|
||||
|
||||
static bool can_merge_ctx(const struct i915_gem_context *prev,
|
||||
const struct i915_gem_context *next)
|
||||
{
|
||||
if (prev != next)
|
||||
return false;
|
||||
|
||||
if (ctx_single_port_submission(prev))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void execlists_dequeue(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *cursor, *last;
|
||||
struct execlist_port *port = engine->execlist_port;
|
||||
bool submit = false;
|
||||
|
||||
last = port->request;
|
||||
if (last)
|
||||
/* WaIdleLiteRestore:bdw,skl
|
||||
* Apply the wa NOOPs to prevent ring:HEAD == req:TAIL
|
||||
* as we resubmit the request. See gen8_emit_request()
|
||||
* for where we prepare the padding after the end of the
|
||||
* request.
|
||||
*/
|
||||
last->tail = last->wa_tail;
|
||||
|
||||
GEM_BUG_ON(port[1].request);
|
||||
|
||||
/* Hardware submission is through 2 ports. Conceptually each port
|
||||
* has a (RING_START, RING_HEAD, RING_TAIL) tuple. RING_START is
|
||||
* static for a context, and unique to each, so we only execute
|
||||
* requests belonging to a single context from each ring. RING_HEAD
|
||||
* is maintained by the CS in the context image, it marks the place
|
||||
* where it got up to last time, and through RING_TAIL we tell the CS
|
||||
* where we want to execute up to this time.
|
||||
*
|
||||
* In this list the requests are in order of execution. Consecutive
|
||||
* requests from the same context are adjacent in the ringbuffer. We
|
||||
* can combine these requests into a single RING_TAIL update:
|
||||
*
|
||||
* RING_HEAD...req1...req2
|
||||
* ^- RING_TAIL
|
||||
* since to execute req2 the CS must first execute req1.
|
||||
*
|
||||
* Our goal then is to point each port to the end of a consecutive
|
||||
* sequence of requests as being the most optimal (fewest wake ups
|
||||
* and context switches) submission.
|
||||
*/
|
||||
|
||||
spin_lock(&engine->execlist_lock);
|
||||
list_for_each_entry(cursor, &engine->execlist_queue, execlist_link) {
|
||||
/* Can we combine this request with the current port? It has to
|
||||
* be the same context/ringbuffer and not have any exceptions
|
||||
* (e.g. GVT saying never to combine contexts).
|
||||
*
|
||||
* If we can combine the requests, we can execute both by
|
||||
* updating the RING_TAIL to point to the end of the second
|
||||
* request, and so we never need to tell the hardware about
|
||||
* the first.
|
||||
*/
|
||||
if (last && !can_merge_ctx(cursor->ctx, last->ctx)) {
|
||||
/* If we are on the second port and cannot combine
|
||||
* this request with the last, then we are done.
|
||||
*/
|
||||
if (port != engine->execlist_port)
|
||||
break;
|
||||
|
||||
/* If GVT overrides us we only ever submit port[0],
|
||||
* leaving port[1] empty. Note that we also have
|
||||
* to be careful that we don't queue the same
|
||||
* context (even though a different request) to
|
||||
* the second port.
|
||||
*/
|
||||
if (ctx_single_port_submission(cursor->ctx))
|
||||
break;
|
||||
|
||||
GEM_BUG_ON(last->ctx == cursor->ctx);
|
||||
|
||||
i915_gem_request_assign(&port->request, last);
|
||||
port++;
|
||||
}
|
||||
last = cursor;
|
||||
submit = true;
|
||||
}
|
||||
if (submit) {
|
||||
/* Decouple all the requests submitted from the queue */
|
||||
engine->execlist_queue.next = &cursor->execlist_link;
|
||||
cursor->execlist_link.prev = &engine->execlist_queue;
|
||||
|
||||
i915_gem_request_assign(&port->request, last);
|
||||
}
|
||||
spin_unlock(&engine->execlist_lock);
|
||||
|
||||
if (submit)
|
||||
execlists_submit_ports(engine);
|
||||
}
|
||||
|
||||
static bool execlists_elsp_idle(struct intel_engine_cs *engine)
|
||||
{
|
||||
return !engine->execlist_port[0].request;
|
||||
}
|
||||
|
||||
static bool execlists_elsp_ready(struct intel_engine_cs *engine)
|
||||
{
|
||||
int port;
|
||||
|
||||
port = 1; /* wait for a free slot */
|
||||
if (engine->disable_lite_restore_wa || engine->preempt_wa)
|
||||
port = 0; /* wait for GPU to be idle before continuing */
|
||||
|
||||
return !engine->execlist_port[port].request;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -543,103 +535,70 @@ get_context_status(struct intel_engine_cs *engine, unsigned int read_pointer,
|
||||
static void intel_lrc_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_private *dev_priv = engine->i915;
|
||||
u32 status_pointer;
|
||||
unsigned int read_pointer, write_pointer;
|
||||
u32 csb[GEN8_CSB_ENTRIES][2];
|
||||
unsigned int csb_read = 0, i;
|
||||
unsigned int submit_contexts = 0;
|
||||
|
||||
intel_uncore_forcewake_get(dev_priv, engine->fw_domains);
|
||||
|
||||
status_pointer = I915_READ_FW(RING_CONTEXT_STATUS_PTR(engine));
|
||||
if (!execlists_elsp_idle(engine)) {
|
||||
u32 __iomem *csb_mmio =
|
||||
dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine));
|
||||
u32 __iomem *buf =
|
||||
dev_priv->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0));
|
||||
unsigned int csb, head, tail;
|
||||
|
||||
read_pointer = engine->next_context_status_buffer;
|
||||
write_pointer = GEN8_CSB_WRITE_PTR(status_pointer);
|
||||
if (read_pointer > write_pointer)
|
||||
write_pointer += GEN8_CSB_ENTRIES;
|
||||
csb = readl(csb_mmio);
|
||||
head = GEN8_CSB_READ_PTR(csb);
|
||||
tail = GEN8_CSB_WRITE_PTR(csb);
|
||||
if (tail < head)
|
||||
tail += GEN8_CSB_ENTRIES;
|
||||
while (head < tail) {
|
||||
unsigned int idx = ++head % GEN8_CSB_ENTRIES;
|
||||
unsigned int status = readl(buf + 2 * idx);
|
||||
|
||||
while (read_pointer < write_pointer) {
|
||||
if (WARN_ON_ONCE(csb_read == GEN8_CSB_ENTRIES))
|
||||
break;
|
||||
csb[csb_read][0] = get_context_status(engine, ++read_pointer,
|
||||
&csb[csb_read][1]);
|
||||
csb_read++;
|
||||
}
|
||||
if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK))
|
||||
continue;
|
||||
|
||||
engine->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES;
|
||||
GEM_BUG_ON(port[0].count == 0);
|
||||
if (--port[0].count == 0) {
|
||||
GEM_BUG_ON(status & GEN8_CTX_STATUS_PREEMPTED);
|
||||
execlists_context_status_change(port[0].request,
|
||||
INTEL_CONTEXT_SCHEDULE_OUT);
|
||||
|
||||
/* Update the read pointer to the old write pointer. Manual ringbuffer
|
||||
* management ftw </sarcasm> */
|
||||
I915_WRITE_FW(RING_CONTEXT_STATUS_PTR(engine),
|
||||
_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
|
||||
engine->next_context_status_buffer << 8));
|
||||
i915_gem_request_put(port[0].request);
|
||||
port[0] = port[1];
|
||||
memset(&port[1], 0, sizeof(port[1]));
|
||||
|
||||
intel_uncore_forcewake_put(dev_priv, engine->fw_domains);
|
||||
engine->preempt_wa = false;
|
||||
}
|
||||
|
||||
spin_lock(&engine->execlist_lock);
|
||||
|
||||
for (i = 0; i < csb_read; i++) {
|
||||
if (unlikely(csb[i][0] & GEN8_CTX_STATUS_PREEMPTED)) {
|
||||
if (csb[i][0] & GEN8_CTX_STATUS_LITE_RESTORE) {
|
||||
if (execlists_check_remove_request(engine, csb[i][1]))
|
||||
WARN(1, "Lite Restored request removed from queue\n");
|
||||
} else
|
||||
WARN(1, "Preemption without Lite Restore\n");
|
||||
GEM_BUG_ON(port[0].count == 0 &&
|
||||
!(status & GEN8_CTX_STATUS_ACTIVE_IDLE));
|
||||
}
|
||||
|
||||
if (csb[i][0] & (GEN8_CTX_STATUS_ACTIVE_IDLE |
|
||||
GEN8_CTX_STATUS_ELEMENT_SWITCH))
|
||||
submit_contexts +=
|
||||
execlists_check_remove_request(engine, csb[i][1]);
|
||||
writel(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK,
|
||||
GEN8_CSB_WRITE_PTR(csb) << 8),
|
||||
csb_mmio);
|
||||
}
|
||||
|
||||
if (submit_contexts) {
|
||||
if (!engine->disable_lite_restore_wa ||
|
||||
(csb[i][0] & GEN8_CTX_STATUS_ACTIVE_IDLE))
|
||||
execlists_unqueue(engine);
|
||||
}
|
||||
if (execlists_elsp_ready(engine))
|
||||
execlists_dequeue(engine);
|
||||
|
||||
spin_unlock(&engine->execlist_lock);
|
||||
|
||||
if (unlikely(submit_contexts > 2))
|
||||
DRM_ERROR("More than two context complete events?\n");
|
||||
intel_uncore_forcewake_put(dev_priv, engine->fw_domains);
|
||||
}
|
||||
|
||||
static void execlists_submit_request(struct drm_i915_gem_request *request)
|
||||
{
|
||||
struct intel_engine_cs *engine = request->engine;
|
||||
struct drm_i915_gem_request *cursor;
|
||||
int num_elements = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_bh(&engine->execlist_lock);
|
||||
spin_lock_irqsave(&engine->execlist_lock, flags);
|
||||
|
||||
list_for_each_entry(cursor, &engine->execlist_queue, execlist_link)
|
||||
if (++num_elements > 2)
|
||||
break;
|
||||
|
||||
if (num_elements > 2) {
|
||||
struct drm_i915_gem_request *tail_req;
|
||||
|
||||
tail_req = list_last_entry(&engine->execlist_queue,
|
||||
struct drm_i915_gem_request,
|
||||
execlist_link);
|
||||
|
||||
if (request->ctx == tail_req->ctx) {
|
||||
WARN(tail_req->elsp_submitted != 0,
|
||||
"More than 2 already-submitted reqs queued\n");
|
||||
list_del(&tail_req->execlist_link);
|
||||
i915_gem_request_put(tail_req);
|
||||
}
|
||||
}
|
||||
|
||||
i915_gem_request_get(request);
|
||||
list_add_tail(&request->execlist_link, &engine->execlist_queue);
|
||||
request->ctx_hw_id = request->ctx->hw_id;
|
||||
if (num_elements == 0)
|
||||
execlists_unqueue(engine);
|
||||
if (execlists_elsp_idle(engine))
|
||||
tasklet_hi_schedule(&engine->irq_tasklet);
|
||||
|
||||
spin_unlock_bh(&engine->execlist_lock);
|
||||
spin_unlock_irqrestore(&engine->execlist_lock, flags);
|
||||
}
|
||||
|
||||
int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request)
|
||||
@ -668,7 +627,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
|
||||
* going any further, as the i915_add_request() call
|
||||
* later on mustn't fail ...
|
||||
*/
|
||||
ret = i915_guc_wq_check_space(request);
|
||||
ret = i915_guc_wq_reserve(request);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -731,6 +690,7 @@ intel_logical_ring_advance(struct drm_i915_gem_request *request)
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_emit(ring, MI_NOOP);
|
||||
intel_ring_advance(ring);
|
||||
request->wa_tail = ring->tail;
|
||||
|
||||
/* We keep the previous context alive until we retire the following
|
||||
* request. This ensures that any the context object is still pinned
|
||||
@ -743,23 +703,6 @@ intel_logical_ring_advance(struct drm_i915_gem_request *request)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void intel_execlists_cancel_requests(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_gem_request *req, *tmp;
|
||||
LIST_HEAD(cancel_list);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&engine->i915->drm.struct_mutex));
|
||||
|
||||
spin_lock_bh(&engine->execlist_lock);
|
||||
list_replace_init(&engine->execlist_queue, &cancel_list);
|
||||
spin_unlock_bh(&engine->execlist_lock);
|
||||
|
||||
list_for_each_entry_safe(req, tmp, &cancel_list, execlist_link) {
|
||||
list_del(&req->execlist_link);
|
||||
i915_gem_request_put(req);
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_lr_context_pin(struct i915_gem_context *ctx,
|
||||
struct intel_engine_cs *engine)
|
||||
{
|
||||
@ -1280,48 +1223,30 @@ static void lrc_init_hws(struct intel_engine_cs *engine)
|
||||
static int gen8_init_common_ring(struct intel_engine_cs *engine)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
unsigned int next_context_status_buffer_hw;
|
||||
int ret;
|
||||
|
||||
ret = intel_mocs_init_engine(engine);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lrc_init_hws(engine);
|
||||
|
||||
I915_WRITE_IMR(engine,
|
||||
~(engine->irq_enable_mask | engine->irq_keep_mask));
|
||||
intel_engine_reset_irq(engine);
|
||||
|
||||
I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
|
||||
|
||||
I915_WRITE(RING_MODE_GEN7(engine),
|
||||
_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
|
||||
_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
|
||||
POSTING_READ(RING_MODE_GEN7(engine));
|
||||
|
||||
/*
|
||||
* Instead of resetting the Context Status Buffer (CSB) read pointer to
|
||||
* zero, we need to read the write pointer from hardware and use its
|
||||
* value because "this register is power context save restored".
|
||||
* Effectively, these states have been observed:
|
||||
*
|
||||
* | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) |
|
||||
* BDW | CSB regs not reset | CSB regs reset |
|
||||
* CHT | CSB regs not reset | CSB regs not reset |
|
||||
* SKL | ? | ? |
|
||||
* BXT | ? | ? |
|
||||
*/
|
||||
next_context_status_buffer_hw =
|
||||
GEN8_CSB_WRITE_PTR(I915_READ(RING_CONTEXT_STATUS_PTR(engine)));
|
||||
|
||||
/*
|
||||
* When the CSB registers are reset (also after power-up / gpu reset),
|
||||
* CSB write pointer is set to all 1's, which is not valid, use '5' in
|
||||
* this special case, so the first element read is CSB[0].
|
||||
*/
|
||||
if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK)
|
||||
next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1);
|
||||
|
||||
engine->next_context_status_buffer = next_context_status_buffer_hw;
|
||||
DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name);
|
||||
|
||||
intel_engine_init_hangcheck(engine);
|
||||
|
||||
return intel_mocs_init_engine(engine);
|
||||
if (!execlists_elsp_idle(engine))
|
||||
execlists_submit_ports(engine);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen8_init_render_ring(struct intel_engine_cs *engine)
|
||||
@ -1357,6 +1282,36 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
|
||||
return init_workarounds_ring(engine);
|
||||
}
|
||||
|
||||
static void reset_common_ring(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = engine->i915;
|
||||
struct execlist_port *port = engine->execlist_port;
|
||||
struct intel_context *ce = &request->ctx->engine[engine->id];
|
||||
|
||||
/* Move the RING_HEAD onto the breadcrumb, past the hanging batch */
|
||||
ce->lrc_reg_state[CTX_RING_HEAD+1] = request->postfix;
|
||||
request->ring->head = request->postfix;
|
||||
request->ring->last_retired_head = -1;
|
||||
intel_ring_update_space(request->ring);
|
||||
|
||||
if (i915.enable_guc_submission)
|
||||
return;
|
||||
|
||||
/* Catch up with any missed context-switch interrupts */
|
||||
I915_WRITE(RING_CONTEXT_STATUS_PTR(engine), _MASKED_FIELD(0xffff, 0));
|
||||
if (request->ctx != port[0].request->ctx) {
|
||||
i915_gem_request_put(port[0].request);
|
||||
port[0] = port[1];
|
||||
memset(&port[1], 0, sizeof(port[1]));
|
||||
}
|
||||
|
||||
/* CS is stopped, and we will resubmit both ports on resume */
|
||||
GEM_BUG_ON(request->ctx != port[0].request->ctx);
|
||||
port[0].count = 0;
|
||||
port[1].count = 0;
|
||||
}
|
||||
|
||||
static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
|
||||
{
|
||||
struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt;
|
||||
@ -1702,10 +1657,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
|
||||
}
|
||||
intel_lr_context_unpin(dev_priv->kernel_context, engine);
|
||||
|
||||
engine->idle_lite_restore_wa = 0;
|
||||
engine->disable_lite_restore_wa = false;
|
||||
engine->ctx_desc_template = 0;
|
||||
|
||||
lrc_destroy_wa_ctx_obj(engine);
|
||||
engine->i915 = NULL;
|
||||
}
|
||||
@ -1723,6 +1674,7 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine)
|
||||
{
|
||||
/* Default vfuncs which can be overriden by each engine. */
|
||||
engine->init_hw = gen8_init_common_ring;
|
||||
engine->reset_hw = reset_common_ring;
|
||||
engine->emit_flush = gen8_emit_flush;
|
||||
engine->emit_request = gen8_emit_request;
|
||||
engine->submit_request = execlists_submit_request;
|
||||
@ -1896,24 +1848,24 @@ make_rpcs(struct drm_i915_private *dev_priv)
|
||||
* must make an explicit request through RPCS for full
|
||||
* enablement.
|
||||
*/
|
||||
if (INTEL_INFO(dev_priv)->has_slice_pg) {
|
||||
if (INTEL_INFO(dev_priv)->sseu.has_slice_pg) {
|
||||
rpcs |= GEN8_RPCS_S_CNT_ENABLE;
|
||||
rpcs |= INTEL_INFO(dev_priv)->slice_total <<
|
||||
rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.slice_mask) <<
|
||||
GEN8_RPCS_S_CNT_SHIFT;
|
||||
rpcs |= GEN8_RPCS_ENABLE;
|
||||
}
|
||||
|
||||
if (INTEL_INFO(dev_priv)->has_subslice_pg) {
|
||||
if (INTEL_INFO(dev_priv)->sseu.has_subslice_pg) {
|
||||
rpcs |= GEN8_RPCS_SS_CNT_ENABLE;
|
||||
rpcs |= INTEL_INFO(dev_priv)->subslice_per_slice <<
|
||||
rpcs |= hweight8(INTEL_INFO(dev_priv)->sseu.subslice_mask) <<
|
||||
GEN8_RPCS_SS_CNT_SHIFT;
|
||||
rpcs |= GEN8_RPCS_ENABLE;
|
||||
}
|
||||
|
||||
if (INTEL_INFO(dev_priv)->has_eu_pg) {
|
||||
rpcs |= INTEL_INFO(dev_priv)->eu_per_subslice <<
|
||||
if (INTEL_INFO(dev_priv)->sseu.has_eu_pg) {
|
||||
rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
|
||||
GEN8_RPCS_EU_MIN_SHIFT;
|
||||
rpcs |= INTEL_INFO(dev_priv)->eu_per_subslice <<
|
||||
rpcs |= INTEL_INFO(dev_priv)->sseu.eu_per_subslice <<
|
||||
GEN8_RPCS_EU_MAX_SHIFT;
|
||||
rpcs |= GEN8_RPCS_ENABLE;
|
||||
}
|
||||
@ -2175,9 +2127,9 @@ error_deref_obj:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void intel_lr_context_reset(struct drm_i915_private *dev_priv,
|
||||
struct i915_gem_context *ctx)
|
||||
void intel_lr_context_resume(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct i915_gem_context *ctx = dev_priv->kernel_context;
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
for_each_engine(engine, dev_priv) {
|
||||
|
@ -87,8 +87,7 @@ void intel_lr_context_unpin(struct i915_gem_context *ctx,
|
||||
|
||||
struct drm_i915_private;
|
||||
|
||||
void intel_lr_context_reset(struct drm_i915_private *dev_priv,
|
||||
struct i915_gem_context *ctx);
|
||||
void intel_lr_context_resume(struct drm_i915_private *dev_priv);
|
||||
uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx,
|
||||
struct intel_engine_cs *engine);
|
||||
|
||||
@ -97,6 +96,4 @@ int intel_sanitize_enable_execlists(struct drm_i915_private *dev_priv,
|
||||
int enable_execlists);
|
||||
void intel_execlists_enable_submission(struct drm_i915_private *dev_priv);
|
||||
|
||||
void intel_execlists_cancel_requests(struct intel_engine_cs *engine);
|
||||
|
||||
#endif /* _INTEL_LRC_H_ */
|
||||
|
@ -230,20 +230,21 @@ static void intel_lvds_pps_init_hw(struct drm_i915_private *dev_priv,
|
||||
I915_WRITE(PP_DIVISOR(0), val);
|
||||
}
|
||||
|
||||
static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
static void intel_pre_enable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(pipe_config->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
int pipe = crtc->pipe;
|
||||
u32 temp;
|
||||
|
||||
if (HAS_PCH_SPLIT(dev)) {
|
||||
if (HAS_PCH_SPLIT(dev_priv)) {
|
||||
assert_fdi_rx_pll_disabled(dev_priv, pipe);
|
||||
assert_shared_dpll_disabled(dev_priv,
|
||||
crtc->config->shared_dpll);
|
||||
pipe_config->shared_dpll);
|
||||
} else {
|
||||
assert_pll_disabled(dev_priv, pipe);
|
||||
}
|
||||
@ -253,7 +254,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
temp = lvds_encoder->init_lvds_val;
|
||||
temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
|
||||
|
||||
if (HAS_PCH_CPT(dev)) {
|
||||
if (HAS_PCH_CPT(dev_priv)) {
|
||||
temp &= ~PORT_TRANS_SEL_MASK;
|
||||
temp |= PORT_TRANS_SEL_CPT(pipe);
|
||||
} else {
|
||||
@ -266,7 +267,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
|
||||
/* set the corresponsding LVDS_BORDER bit */
|
||||
temp &= ~LVDS_BORDER_ENABLE;
|
||||
temp |= crtc->config->gmch_pfit.lvds_border_bits;
|
||||
temp |= pipe_config->gmch_pfit.lvds_border_bits;
|
||||
/* Set the B0-B3 data pairs corresponding to whether we're going to
|
||||
* set the DPLLs for dual-channel mode or not.
|
||||
*/
|
||||
@ -289,7 +290,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
if (IS_GEN4(dev_priv)) {
|
||||
/* Bspec wording suggests that LVDS port dithering only exists
|
||||
* for 18bpp panels. */
|
||||
if (crtc->config->dither && crtc->config->pipe_bpp == 18)
|
||||
if (pipe_config->dither && pipe_config->pipe_bpp == 18)
|
||||
temp |= LVDS_ENABLE_DITHER;
|
||||
else
|
||||
temp &= ~LVDS_ENABLE_DITHER;
|
||||
@ -306,7 +307,9 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
|
||||
/**
|
||||
* Sets the power state for the panel.
|
||||
*/
|
||||
static void intel_enable_lvds(struct intel_encoder *encoder)
|
||||
static void intel_enable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
@ -324,11 +327,12 @@ static void intel_enable_lvds(struct intel_encoder *encoder)
|
||||
intel_panel_enable_backlight(intel_connector);
|
||||
}
|
||||
|
||||
static void intel_disable_lvds(struct intel_encoder *encoder)
|
||||
static void intel_disable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
|
||||
I915_WRITE(PP_CONTROL(0), I915_READ(PP_CONTROL(0)) & ~PANEL_POWER_ON);
|
||||
if (intel_wait_for_register(dev_priv, PP_STATUS(0), PP_ON, 0, 1000))
|
||||
@ -338,7 +342,10 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
|
||||
POSTING_READ(lvds_encoder->reg);
|
||||
}
|
||||
|
||||
static void gmch_disable_lvds(struct intel_encoder *encoder)
|
||||
static void gmch_disable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
|
||||
{
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct intel_connector *intel_connector =
|
||||
@ -346,10 +353,12 @@ static void gmch_disable_lvds(struct intel_encoder *encoder)
|
||||
|
||||
intel_panel_disable_backlight(intel_connector);
|
||||
|
||||
intel_disable_lvds(encoder);
|
||||
intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static void pch_disable_lvds(struct intel_encoder *encoder)
|
||||
static void pch_disable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base);
|
||||
struct intel_connector *intel_connector =
|
||||
@ -358,9 +367,11 @@ static void pch_disable_lvds(struct intel_encoder *encoder)
|
||||
intel_panel_disable_backlight(intel_connector);
|
||||
}
|
||||
|
||||
static void pch_post_disable_lvds(struct intel_encoder *encoder)
|
||||
static void pch_post_disable_lvds(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_disable_lvds(encoder);
|
||||
intel_disable_lvds(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static enum drm_mode_status
|
||||
@ -382,7 +393,8 @@ intel_lvds_mode_valid(struct drm_connector *connector,
|
||||
}
|
||||
|
||||
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
struct intel_lvds_encoder *lvds_encoder =
|
||||
|
@ -1047,6 +1047,23 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int intel_use_opregion_panel_type_callback(const struct dmi_system_id *id)
|
||||
{
|
||||
DRM_INFO("Using panel type from OpRegion on %s\n", id->ident);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id intel_use_opregion_panel_type[] = {
|
||||
{
|
||||
.callback = intel_use_opregion_panel_type_callback,
|
||||
.ident = "Conrac GmbH IX45GM2",
|
||||
.matches = {DMI_MATCH(DMI_SYS_VENDOR, "Conrac GmbH"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "IX45GM2"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
int
|
||||
intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
@ -1072,6 +1089,16 @@ intel_opregion_get_panel_type(struct drm_i915_private *dev_priv)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* So far we know that some machined must use it, others must not use it.
|
||||
* There doesn't seem to be any way to determine which way to go, except
|
||||
* via a quirk list :(
|
||||
*/
|
||||
if (!dmi_check_system(intel_use_opregion_panel_type)) {
|
||||
DRM_DEBUG_KMS("Ignoring OpRegion panel type (%d)\n", ret - 1);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME On Dell XPS 13 9350 the OpRegion panel type (0) gives us
|
||||
* low vswing for eDP, whereas the VBT panel type (2) gives us normal
|
||||
|
@ -1430,10 +1430,11 @@ static int lpt_setup_backlight(struct intel_connector *connector, enum pipe unus
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
val = lpt_get_backlight(connector);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
|
||||
panel->backlight.level != 0;
|
||||
panel->backlight.enabled = pch_ctl1 & BLM_PCH_PWM_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1459,11 +1460,13 @@ static int pch_setup_backlight(struct intel_connector *connector, enum pipe unus
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
val = pch_get_backlight(connector);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
|
||||
panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
|
||||
(pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
|
||||
(pch_ctl1 & BLM_PCH_PWM_ENABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1498,9 +1501,11 @@ static int i9xx_setup_backlight(struct intel_connector *connector, enum pipe unu
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
val = i9xx_get_backlight(connector);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
panel->backlight.enabled = panel->backlight.level != 0;
|
||||
panel->backlight.enabled = val != 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1530,10 +1535,11 @@ static int i965_setup_backlight(struct intel_connector *connector, enum pipe unu
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
val = i9xx_get_backlight(connector);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
|
||||
panel->backlight.level != 0;
|
||||
panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1562,10 +1568,11 @@ static int vlv_setup_backlight(struct intel_connector *connector, enum pipe pipe
|
||||
panel->backlight.min = get_backlight_min_vbt(connector);
|
||||
|
||||
val = _vlv_get_backlight(dev_priv, pipe);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
|
||||
panel->backlight.level != 0;
|
||||
panel->backlight.enabled = ctl2 & BLM_PWM_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1607,10 +1614,11 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused)
|
||||
return -ENODEV;
|
||||
|
||||
val = bxt_get_backlight(connector);
|
||||
panel->backlight.level = intel_panel_compute_brightness(connector, val);
|
||||
val = intel_panel_compute_brightness(connector, val);
|
||||
panel->backlight.level = clamp(val, panel->backlight.min,
|
||||
panel->backlight.max);
|
||||
|
||||
panel->backlight.enabled = (pwm_ctl & BXT_BLC_PWM_ENABLE) &&
|
||||
panel->backlight.level != 0;
|
||||
panel->backlight.enabled = pwm_ctl & BXT_BLC_PWM_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2853,13 +2853,7 @@ bool ilk_disable_lp_wm(struct drm_device *dev)
|
||||
return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
|
||||
}
|
||||
|
||||
/*
|
||||
* On gen9, we need to allocate Display Data Buffer (DDB) portions to the
|
||||
* different active planes.
|
||||
*/
|
||||
|
||||
#define SKL_DDB_SIZE 896 /* in blocks */
|
||||
#define BXT_DDB_SIZE 512
|
||||
#define SKL_SAGV_BLOCK_TIME 30 /* µs */
|
||||
|
||||
/*
|
||||
* Return the index of a plane in the SKL DDB and wm result arrays. Primary
|
||||
@ -2883,6 +2877,153 @@ skl_wm_plane_id(const struct intel_plane *plane)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SAGV dynamically adjusts the system agent voltage and clock frequencies
|
||||
* depending on power and performance requirements. The display engine access
|
||||
* to system memory is blocked during the adjustment time. Because of the
|
||||
* blocking time, having this enabled can cause full system hangs and/or pipe
|
||||
* underruns if we don't meet all of the following requirements:
|
||||
*
|
||||
* - <= 1 pipe enabled
|
||||
* - All planes can enable watermarks for latencies >= SAGV engine block time
|
||||
* - We're not using an interlaced display configuration
|
||||
*/
|
||||
int
|
||||
skl_enable_sagv(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (dev_priv->skl_sagv_status == I915_SKL_SAGV_NOT_CONTROLLED ||
|
||||
dev_priv->skl_sagv_status == I915_SKL_SAGV_ENABLED)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_KMS("Enabling the SAGV\n");
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
ret = sandybridge_pcode_write(dev_priv, GEN9_PCODE_SAGV_CONTROL,
|
||||
GEN9_SAGV_ENABLE);
|
||||
|
||||
/* We don't need to wait for the SAGV when enabling */
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
/*
|
||||
* Some skl systems, pre-release machines in particular,
|
||||
* don't actually have an SAGV.
|
||||
*/
|
||||
if (ret == -ENXIO) {
|
||||
DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n");
|
||||
dev_priv->skl_sagv_status = I915_SKL_SAGV_NOT_CONTROLLED;
|
||||
return 0;
|
||||
} else if (ret < 0) {
|
||||
DRM_ERROR("Failed to enable the SAGV\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_priv->skl_sagv_status = I915_SKL_SAGV_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
skl_do_sagv_disable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret;
|
||||
uint32_t temp = GEN9_SAGV_DISABLE;
|
||||
|
||||
ret = sandybridge_pcode_read(dev_priv, GEN9_PCODE_SAGV_CONTROL,
|
||||
&temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
else
|
||||
return temp & GEN9_SAGV_IS_DISABLED;
|
||||
}
|
||||
|
||||
int
|
||||
skl_disable_sagv(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
int ret, result;
|
||||
|
||||
if (dev_priv->skl_sagv_status == I915_SKL_SAGV_NOT_CONTROLLED ||
|
||||
dev_priv->skl_sagv_status == I915_SKL_SAGV_DISABLED)
|
||||
return 0;
|
||||
|
||||
DRM_DEBUG_KMS("Disabling the SAGV\n");
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
|
||||
/* bspec says to keep retrying for at least 1 ms */
|
||||
ret = wait_for(result = skl_do_sagv_disable(dev_priv), 1);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
if (ret == -ETIMEDOUT) {
|
||||
DRM_ERROR("Request to disable SAGV timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some skl systems, pre-release machines in particular,
|
||||
* don't actually have an SAGV.
|
||||
*/
|
||||
if (result == -ENXIO) {
|
||||
DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n");
|
||||
dev_priv->skl_sagv_status = I915_SKL_SAGV_NOT_CONTROLLED;
|
||||
return 0;
|
||||
} else if (result < 0) {
|
||||
DRM_ERROR("Failed to disable the SAGV\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
dev_priv->skl_sagv_status = I915_SKL_SAGV_DISABLED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool skl_can_enable_sagv(struct drm_atomic_state *state)
|
||||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
|
||||
struct drm_crtc *crtc;
|
||||
enum pipe pipe;
|
||||
int level, plane;
|
||||
|
||||
/*
|
||||
* SKL workaround: bspec recommends we disable the SAGV when we have
|
||||
* more then one pipe enabled
|
||||
*
|
||||
* If there are no active CRTCs, no additional checks need be performed
|
||||
*/
|
||||
if (hweight32(intel_state->active_crtcs) == 0)
|
||||
return true;
|
||||
else if (hweight32(intel_state->active_crtcs) > 1)
|
||||
return false;
|
||||
|
||||
/* Since we're now guaranteed to only have one active CRTC... */
|
||||
pipe = ffs(intel_state->active_crtcs) - 1;
|
||||
crtc = dev_priv->pipe_to_crtc_mapping[pipe];
|
||||
|
||||
if (crtc->state->mode.flags & DRM_MODE_FLAG_INTERLACE)
|
||||
return false;
|
||||
|
||||
for_each_plane(dev_priv, pipe, plane) {
|
||||
/* Skip this plane if it's not enabled */
|
||||
if (intel_state->wm_results.plane[pipe][plane][0] == 0)
|
||||
continue;
|
||||
|
||||
/* Find the highest enabled wm level for this plane */
|
||||
for (level = ilk_wm_max_level(dev);
|
||||
intel_state->wm_results.plane[pipe][plane][level] == 0; --level)
|
||||
{ }
|
||||
|
||||
/*
|
||||
* If any of the planes on this pipe don't enable wm levels
|
||||
* that incur memory latencies higher then 30µs we can't enable
|
||||
* the SAGV
|
||||
*/
|
||||
if (dev_priv->wm.skl_latency[level] < SKL_SAGV_BLOCK_TIME)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
|
||||
const struct intel_crtc_state *cstate,
|
||||
@ -2909,10 +3050,8 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
|
||||
else
|
||||
*num_active = hweight32(dev_priv->active_crtcs);
|
||||
|
||||
if (IS_BROXTON(dev))
|
||||
ddb_size = BXT_DDB_SIZE;
|
||||
else
|
||||
ddb_size = SKL_DDB_SIZE;
|
||||
ddb_size = INTEL_INFO(dev_priv)->ddb_size;
|
||||
WARN_ON(ddb_size == 0);
|
||||
|
||||
ddb_size -= 4; /* 4 blocks for bypass path allocation */
|
||||
|
||||
@ -3688,183 +3827,82 @@ static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
|
||||
I915_WRITE(reg, 0);
|
||||
}
|
||||
|
||||
static void skl_write_wm_values(struct drm_i915_private *dev_priv,
|
||||
const struct skl_wm_values *new)
|
||||
void skl_write_plane_wm(struct intel_crtc *intel_crtc,
|
||||
const struct skl_wm_values *wm,
|
||||
int plane)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct intel_crtc *crtc;
|
||||
struct drm_crtc *crtc = &intel_crtc->base;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
int level, max_level = ilk_wm_max_level(dev);
|
||||
enum pipe pipe = intel_crtc->pipe;
|
||||
|
||||
for_each_intel_crtc(dev, crtc) {
|
||||
int i, level, max_level = ilk_wm_max_level(dev);
|
||||
enum pipe pipe = crtc->pipe;
|
||||
|
||||
if ((new->dirty_pipes & drm_crtc_mask(&crtc->base)) == 0)
|
||||
continue;
|
||||
if (!crtc->active)
|
||||
continue;
|
||||
|
||||
I915_WRITE(PIPE_WM_LINETIME(pipe), new->wm_linetime[pipe]);
|
||||
|
||||
for (level = 0; level <= max_level; level++) {
|
||||
for (i = 0; i < intel_num_planes(crtc); i++)
|
||||
I915_WRITE(PLANE_WM(pipe, i, level),
|
||||
new->plane[pipe][i][level]);
|
||||
I915_WRITE(CUR_WM(pipe, level),
|
||||
new->plane[pipe][PLANE_CURSOR][level]);
|
||||
}
|
||||
for (i = 0; i < intel_num_planes(crtc); i++)
|
||||
I915_WRITE(PLANE_WM_TRANS(pipe, i),
|
||||
new->plane_trans[pipe][i]);
|
||||
I915_WRITE(CUR_WM_TRANS(pipe),
|
||||
new->plane_trans[pipe][PLANE_CURSOR]);
|
||||
|
||||
for (i = 0; i < intel_num_planes(crtc); i++) {
|
||||
skl_ddb_entry_write(dev_priv,
|
||||
PLANE_BUF_CFG(pipe, i),
|
||||
&new->ddb.plane[pipe][i]);
|
||||
skl_ddb_entry_write(dev_priv,
|
||||
PLANE_NV12_BUF_CFG(pipe, i),
|
||||
&new->ddb.y_plane[pipe][i]);
|
||||
}
|
||||
|
||||
skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
|
||||
&new->ddb.plane[pipe][PLANE_CURSOR]);
|
||||
for (level = 0; level <= max_level; level++) {
|
||||
I915_WRITE(PLANE_WM(pipe, plane, level),
|
||||
wm->plane[pipe][plane][level]);
|
||||
}
|
||||
I915_WRITE(PLANE_WM_TRANS(pipe, plane), wm->plane_trans[pipe][plane]);
|
||||
|
||||
skl_ddb_entry_write(dev_priv, PLANE_BUF_CFG(pipe, plane),
|
||||
&wm->ddb.plane[pipe][plane]);
|
||||
skl_ddb_entry_write(dev_priv, PLANE_NV12_BUF_CFG(pipe, plane),
|
||||
&wm->ddb.y_plane[pipe][plane]);
|
||||
}
|
||||
|
||||
/*
|
||||
* When setting up a new DDB allocation arrangement, we need to correctly
|
||||
* sequence the times at which the new allocations for the pipes are taken into
|
||||
* account or we'll have pipes fetching from space previously allocated to
|
||||
* another pipe.
|
||||
*
|
||||
* Roughly the sequence looks like:
|
||||
* 1. re-allocate the pipe(s) with the allocation being reduced and not
|
||||
* overlapping with a previous light-up pipe (another way to put it is:
|
||||
* pipes with their new allocation strickly included into their old ones).
|
||||
* 2. re-allocate the other pipes that get their allocation reduced
|
||||
* 3. allocate the pipes having their allocation increased
|
||||
*
|
||||
* Steps 1. and 2. are here to take care of the following case:
|
||||
* - Initially DDB looks like this:
|
||||
* | B | C |
|
||||
* - enable pipe A.
|
||||
* - pipe B has a reduced DDB allocation that overlaps with the old pipe C
|
||||
* allocation
|
||||
* | A | B | C |
|
||||
*
|
||||
* We need to sequence the re-allocation: C, B, A (and not B, C, A).
|
||||
*/
|
||||
|
||||
static void
|
||||
skl_wm_flush_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, int pass)
|
||||
void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
|
||||
const struct skl_wm_values *wm)
|
||||
{
|
||||
int plane;
|
||||
struct drm_crtc *crtc = &intel_crtc->base;
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
int level, max_level = ilk_wm_max_level(dev);
|
||||
enum pipe pipe = intel_crtc->pipe;
|
||||
|
||||
DRM_DEBUG_KMS("flush pipe %c (pass %d)\n", pipe_name(pipe), pass);
|
||||
|
||||
for_each_plane(dev_priv, pipe, plane) {
|
||||
I915_WRITE(PLANE_SURF(pipe, plane),
|
||||
I915_READ(PLANE_SURF(pipe, plane)));
|
||||
for (level = 0; level <= max_level; level++) {
|
||||
I915_WRITE(CUR_WM(pipe, level),
|
||||
wm->plane[pipe][PLANE_CURSOR][level]);
|
||||
}
|
||||
I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe)));
|
||||
I915_WRITE(CUR_WM_TRANS(pipe), wm->plane_trans[pipe][PLANE_CURSOR]);
|
||||
|
||||
skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
|
||||
&wm->ddb.plane[pipe][PLANE_CURSOR]);
|
||||
}
|
||||
|
||||
static bool
|
||||
skl_ddb_allocation_included(const struct skl_ddb_allocation *old,
|
||||
const struct skl_ddb_allocation *new,
|
||||
enum pipe pipe)
|
||||
bool skl_ddb_allocation_equals(const struct skl_ddb_allocation *old,
|
||||
const struct skl_ddb_allocation *new,
|
||||
enum pipe pipe)
|
||||
{
|
||||
uint16_t old_size, new_size;
|
||||
|
||||
old_size = skl_ddb_entry_size(&old->pipe[pipe]);
|
||||
new_size = skl_ddb_entry_size(&new->pipe[pipe]);
|
||||
|
||||
return old_size != new_size &&
|
||||
new->pipe[pipe].start >= old->pipe[pipe].start &&
|
||||
new->pipe[pipe].end <= old->pipe[pipe].end;
|
||||
return new->pipe[pipe].start == old->pipe[pipe].start &&
|
||||
new->pipe[pipe].end == old->pipe[pipe].end;
|
||||
}
|
||||
|
||||
static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
|
||||
struct skl_wm_values *new_values)
|
||||
static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
|
||||
const struct skl_ddb_entry *b)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct skl_ddb_allocation *cur_ddb, *new_ddb;
|
||||
bool reallocated[I915_MAX_PIPES] = {};
|
||||
struct intel_crtc *crtc;
|
||||
enum pipe pipe;
|
||||
return a->start < b->end && b->start < a->end;
|
||||
}
|
||||
|
||||
new_ddb = &new_values->ddb;
|
||||
cur_ddb = &dev_priv->wm.skl_hw.ddb;
|
||||
bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
|
||||
const struct skl_ddb_allocation *old,
|
||||
const struct skl_ddb_allocation *new,
|
||||
enum pipe pipe)
|
||||
{
|
||||
struct drm_device *dev = state->dev;
|
||||
struct intel_crtc *intel_crtc;
|
||||
enum pipe otherp;
|
||||
|
||||
/*
|
||||
* First pass: flush the pipes with the new allocation contained into
|
||||
* the old space.
|
||||
*
|
||||
* We'll wait for the vblank on those pipes to ensure we can safely
|
||||
* re-allocate the freed space without this pipe fetching from it.
|
||||
*/
|
||||
for_each_intel_crtc(dev, crtc) {
|
||||
if (!crtc->active)
|
||||
for_each_intel_crtc(dev, intel_crtc) {
|
||||
otherp = intel_crtc->pipe;
|
||||
|
||||
if (otherp == pipe)
|
||||
continue;
|
||||
|
||||
pipe = crtc->pipe;
|
||||
|
||||
if (!skl_ddb_allocation_included(cur_ddb, new_ddb, pipe))
|
||||
continue;
|
||||
|
||||
skl_wm_flush_pipe(dev_priv, pipe, 1);
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
|
||||
reallocated[pipe] = true;
|
||||
if (skl_ddb_entries_overlap(&new->pipe[pipe],
|
||||
&old->pipe[otherp]))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Second pass: flush the pipes that are having their allocation
|
||||
* reduced, but overlapping with a previous allocation.
|
||||
*
|
||||
* Here as well we need to wait for the vblank to make sure the freed
|
||||
* space is not used anymore.
|
||||
*/
|
||||
for_each_intel_crtc(dev, crtc) {
|
||||
if (!crtc->active)
|
||||
continue;
|
||||
|
||||
pipe = crtc->pipe;
|
||||
|
||||
if (reallocated[pipe])
|
||||
continue;
|
||||
|
||||
if (skl_ddb_entry_size(&new_ddb->pipe[pipe]) <
|
||||
skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
|
||||
skl_wm_flush_pipe(dev_priv, pipe, 2);
|
||||
intel_wait_for_vblank(dev, pipe);
|
||||
reallocated[pipe] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Third pass: flush the pipes that got more space allocated.
|
||||
*
|
||||
* We don't need to actively wait for the update here, next vblank
|
||||
* will just get more DDB space with the correct WM values.
|
||||
*/
|
||||
for_each_intel_crtc(dev, crtc) {
|
||||
if (!crtc->active)
|
||||
continue;
|
||||
|
||||
pipe = crtc->pipe;
|
||||
|
||||
/*
|
||||
* At this point, only the pipes more space than before are
|
||||
* left to re-allocate.
|
||||
*/
|
||||
if (reallocated[pipe])
|
||||
continue;
|
||||
|
||||
skl_wm_flush_pipe(dev_priv, pipe, 3);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int skl_update_pipe_wm(struct drm_crtc_state *cstate,
|
||||
@ -3964,11 +4002,33 @@ skl_compute_ddb(struct drm_atomic_state *state)
|
||||
ret = skl_allocate_pipe_ddb(cstate, ddb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_add_affected_planes(state, &intel_crtc->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
skl_copy_wm_for_pipe(struct skl_wm_values *dst,
|
||||
struct skl_wm_values *src,
|
||||
enum pipe pipe)
|
||||
{
|
||||
dst->wm_linetime[pipe] = src->wm_linetime[pipe];
|
||||
memcpy(dst->plane[pipe], src->plane[pipe],
|
||||
sizeof(dst->plane[pipe]));
|
||||
memcpy(dst->plane_trans[pipe], src->plane_trans[pipe],
|
||||
sizeof(dst->plane_trans[pipe]));
|
||||
|
||||
dst->ddb.pipe[pipe] = src->ddb.pipe[pipe];
|
||||
memcpy(dst->ddb.y_plane[pipe], src->ddb.y_plane[pipe],
|
||||
sizeof(dst->ddb.y_plane[pipe]));
|
||||
memcpy(dst->ddb.plane[pipe], src->ddb.plane[pipe],
|
||||
sizeof(dst->ddb.plane[pipe]));
|
||||
}
|
||||
|
||||
static int
|
||||
skl_compute_wm(struct drm_atomic_state *state)
|
||||
{
|
||||
@ -4041,8 +4101,10 @@ static void skl_update_wm(struct drm_crtc *crtc)
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct skl_wm_values *results = &dev_priv->wm.skl_results;
|
||||
struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
|
||||
struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
|
||||
struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
|
||||
enum pipe pipe = intel_crtc->pipe;
|
||||
|
||||
if ((results->dirty_pipes & drm_crtc_mask(crtc)) == 0)
|
||||
return;
|
||||
@ -4051,11 +4113,22 @@ static void skl_update_wm(struct drm_crtc *crtc)
|
||||
|
||||
mutex_lock(&dev_priv->wm.wm_mutex);
|
||||
|
||||
skl_write_wm_values(dev_priv, results);
|
||||
skl_flush_wm_values(dev_priv, results);
|
||||
/*
|
||||
* If this pipe isn't active already, we're going to be enabling it
|
||||
* very soon. Since it's safe to update a pipe's ddb allocation while
|
||||
* the pipe's shut off, just do so here. Already active pipes will have
|
||||
* their watermarks updated once we update their planes.
|
||||
*/
|
||||
if (crtc->state->active_changed) {
|
||||
int plane;
|
||||
|
||||
/* store the new configuration */
|
||||
dev_priv->wm.skl_hw = *results;
|
||||
for (plane = 0; plane < intel_num_planes(intel_crtc); plane++)
|
||||
skl_write_plane_wm(intel_crtc, results, plane);
|
||||
|
||||
skl_write_cursor_wm(intel_crtc, results);
|
||||
}
|
||||
|
||||
skl_copy_wm_for_pipe(hw_vals, results, pipe);
|
||||
|
||||
mutex_unlock(&dev_priv->wm.wm_mutex);
|
||||
}
|
||||
@ -5550,7 +5623,7 @@ static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv)
|
||||
|
||||
val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
|
||||
|
||||
switch (INTEL_INFO(dev_priv)->eu_total) {
|
||||
switch (INTEL_INFO(dev_priv)->sseu.eu_total) {
|
||||
case 8:
|
||||
/* (2 * 4) config */
|
||||
rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
|
||||
@ -6691,9 +6764,7 @@ void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
|
||||
|
||||
if (IS_IRONLAKE_M(dev_priv)) {
|
||||
ironlake_enable_drps(dev_priv);
|
||||
mutex_lock(&dev_priv->drm.struct_mutex);
|
||||
intel_init_emon(dev_priv);
|
||||
mutex_unlock(&dev_priv->drm.struct_mutex);
|
||||
} else if (INTEL_INFO(dev_priv)->gen >= 6) {
|
||||
/*
|
||||
* PCU communication is slow and this doesn't need to be
|
||||
@ -7659,8 +7730,54 @@ void intel_init_pm(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int gen6_check_mailbox_status(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
uint32_t flags =
|
||||
I915_READ_FW(GEN6_PCODE_MAILBOX) & GEN6_PCODE_ERROR_MASK;
|
||||
|
||||
switch (flags) {
|
||||
case GEN6_PCODE_SUCCESS:
|
||||
return 0;
|
||||
case GEN6_PCODE_UNIMPLEMENTED_CMD:
|
||||
case GEN6_PCODE_ILLEGAL_CMD:
|
||||
return -ENXIO;
|
||||
case GEN6_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
|
||||
case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
|
||||
return -EOVERFLOW;
|
||||
case GEN6_PCODE_TIMEOUT:
|
||||
return -ETIMEDOUT;
|
||||
default:
|
||||
MISSING_CASE(flags)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int gen7_check_mailbox_status(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
uint32_t flags =
|
||||
I915_READ_FW(GEN6_PCODE_MAILBOX) & GEN6_PCODE_ERROR_MASK;
|
||||
|
||||
switch (flags) {
|
||||
case GEN6_PCODE_SUCCESS:
|
||||
return 0;
|
||||
case GEN6_PCODE_ILLEGAL_CMD:
|
||||
return -ENXIO;
|
||||
case GEN7_PCODE_TIMEOUT:
|
||||
return -ETIMEDOUT;
|
||||
case GEN7_PCODE_ILLEGAL_DATA:
|
||||
return -EINVAL;
|
||||
case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE:
|
||||
return -EOVERFLOW;
|
||||
default:
|
||||
MISSING_CASE(flags);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val)
|
||||
{
|
||||
int status;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
|
||||
|
||||
/* GEN6_PCODE_* are outside of the forcewake domain, we can
|
||||
@ -7687,12 +7804,25 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val
|
||||
*val = I915_READ_FW(GEN6_PCODE_DATA);
|
||||
I915_WRITE_FW(GEN6_PCODE_DATA, 0);
|
||||
|
||||
if (INTEL_GEN(dev_priv) > 6)
|
||||
status = gen7_check_mailbox_status(dev_priv);
|
||||
else
|
||||
status = gen6_check_mailbox_status(dev_priv);
|
||||
|
||||
if (status) {
|
||||
DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sandybridge_pcode_write(struct drm_i915_private *dev_priv,
|
||||
u32 mbox, u32 val)
|
||||
u32 mbox, u32 val)
|
||||
{
|
||||
int status;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
|
||||
|
||||
/* GEN6_PCODE_* are outside of the forcewake domain, we can
|
||||
@ -7717,6 +7847,17 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv,
|
||||
|
||||
I915_WRITE_FW(GEN6_PCODE_DATA, 0);
|
||||
|
||||
if (INTEL_GEN(dev_priv) > 6)
|
||||
status = gen7_check_mailbox_status(dev_priv);
|
||||
else
|
||||
status = gen6_check_mailbox_status(dev_priv);
|
||||
|
||||
if (status) {
|
||||
DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -255,14 +255,14 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp)
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
||||
uint32_t max_sleep_time = 0x1f;
|
||||
/* Lately it was identified that depending on panel idle frame count
|
||||
* calculated at HW can be off by 1. So let's use what came
|
||||
* from VBT + 1.
|
||||
* There are also other cases where panel demands at least 4
|
||||
* but VBT is not being set. To cover these 2 cases lets use
|
||||
* at least 5 when VBT isn't set to be on the safest side.
|
||||
/*
|
||||
* Let's respect VBT in case VBT asks a higher idle_frame value.
|
||||
* Let's use 6 as the minimum to cover all known cases including
|
||||
* the off-by-one issue that HW has in some cases. Also there are
|
||||
* cases where sink should be able to train
|
||||
* with the 5 or 6 idle patterns.
|
||||
*/
|
||||
uint32_t idle_frames = dev_priv->vbt.psr.idle_frames + 1;
|
||||
uint32_t idle_frames = max(6, dev_priv->vbt.psr.idle_frames);
|
||||
uint32_t val = EDP_PSR_ENABLE;
|
||||
|
||||
val |= max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT;
|
||||
|
@ -559,10 +559,12 @@ static int init_ring_common(struct intel_engine_cs *engine)
|
||||
}
|
||||
}
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev_priv))
|
||||
intel_ring_setup_status_page(engine);
|
||||
else
|
||||
if (HWS_NEEDS_PHYSICAL(dev_priv))
|
||||
ring_setup_phys_status_page(engine);
|
||||
else
|
||||
intel_ring_setup_status_page(engine);
|
||||
|
||||
intel_engine_reset_irq(engine);
|
||||
|
||||
/* Enforce ordering by reading HEAD register back */
|
||||
I915_READ_HEAD(engine);
|
||||
@ -577,34 +579,33 @@ static int init_ring_common(struct intel_engine_cs *engine)
|
||||
if (I915_READ_HEAD(engine))
|
||||
DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
|
||||
engine->name, I915_READ_HEAD(engine));
|
||||
I915_WRITE_HEAD(engine, 0);
|
||||
(void)I915_READ_HEAD(engine);
|
||||
|
||||
intel_ring_update_space(ring);
|
||||
I915_WRITE_HEAD(engine, ring->head);
|
||||
I915_WRITE_TAIL(engine, ring->tail);
|
||||
(void)I915_READ_TAIL(engine);
|
||||
|
||||
I915_WRITE_CTL(engine,
|
||||
((ring->size - PAGE_SIZE) & RING_NR_PAGES)
|
||||
| RING_VALID);
|
||||
|
||||
/* If the head is still not zero, the ring is dead */
|
||||
if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
|
||||
I915_READ_START(engine) == i915_ggtt_offset(ring->vma) &&
|
||||
(I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
|
||||
if (intel_wait_for_register_fw(dev_priv, RING_CTL(engine->mmio_base),
|
||||
RING_VALID, RING_VALID,
|
||||
50)) {
|
||||
DRM_ERROR("%s initialization failed "
|
||||
"ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08x]\n",
|
||||
"ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n",
|
||||
engine->name,
|
||||
I915_READ_CTL(engine),
|
||||
I915_READ_CTL(engine) & RING_VALID,
|
||||
I915_READ_HEAD(engine), I915_READ_TAIL(engine),
|
||||
I915_READ_HEAD(engine), ring->head,
|
||||
I915_READ_TAIL(engine), ring->tail,
|
||||
I915_READ_START(engine),
|
||||
i915_ggtt_offset(ring->vma));
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ring->last_retired_head = -1;
|
||||
ring->head = I915_READ_HEAD(engine);
|
||||
ring->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
|
||||
intel_ring_update_space(ring);
|
||||
|
||||
intel_engine_init_hangcheck(engine);
|
||||
|
||||
out:
|
||||
@ -613,6 +614,15 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void reset_ring_common(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *request)
|
||||
{
|
||||
struct intel_ring *ring = request->ring;
|
||||
|
||||
ring->head = request->postfix;
|
||||
ring->last_retired_head = -1;
|
||||
}
|
||||
|
||||
static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
|
||||
{
|
||||
struct intel_ring *ring = req->ring;
|
||||
@ -951,7 +961,7 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
|
||||
* Only consider slices where one, and only one, subslice has 7
|
||||
* EUs
|
||||
*/
|
||||
if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
|
||||
if (!is_power_of_2(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@ -960,7 +970,7 @@ static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
|
||||
*
|
||||
* -> 0 <= ss <= 3;
|
||||
*/
|
||||
ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
|
||||
ss = ffs(INTEL_INFO(dev_priv)->sseu.subslice_7eu[i]) - 1;
|
||||
vals[i] = 3 - ss;
|
||||
}
|
||||
|
||||
@ -2007,7 +2017,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
|
||||
}
|
||||
ring->vma = vma;
|
||||
|
||||
list_add(&ring->link, &engine->buffers);
|
||||
return ring;
|
||||
}
|
||||
|
||||
@ -2015,7 +2024,6 @@ void
|
||||
intel_ring_free(struct intel_ring *ring)
|
||||
{
|
||||
i915_vma_put(ring->vma);
|
||||
list_del(&ring->link);
|
||||
kfree(ring);
|
||||
}
|
||||
|
||||
@ -2109,13 +2117,13 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev_priv)) {
|
||||
ret = init_status_page(engine);
|
||||
if (HWS_NEEDS_PHYSICAL(dev_priv)) {
|
||||
WARN_ON(engine->id != RCS);
|
||||
ret = init_phys_status_page(engine);
|
||||
if (ret)
|
||||
goto error;
|
||||
} else {
|
||||
WARN_ON(engine->id != RCS);
|
||||
ret = init_phys_status_page(engine);
|
||||
ret = init_status_page(engine);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
@ -2155,11 +2163,11 @@ void intel_engine_cleanup(struct intel_engine_cs *engine)
|
||||
if (engine->cleanup)
|
||||
engine->cleanup(engine);
|
||||
|
||||
if (I915_NEED_GFX_HWS(dev_priv)) {
|
||||
cleanup_status_page(engine);
|
||||
} else {
|
||||
if (HWS_NEEDS_PHYSICAL(dev_priv)) {
|
||||
WARN_ON(engine->id != RCS);
|
||||
cleanup_phys_status_page(engine);
|
||||
} else {
|
||||
cleanup_status_page(engine);
|
||||
}
|
||||
|
||||
intel_engine_cleanup_common(engine);
|
||||
@ -2169,6 +2177,16 @@ void intel_engine_cleanup(struct intel_engine_cs *engine)
|
||||
engine->i915 = NULL;
|
||||
}
|
||||
|
||||
void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
|
||||
for_each_engine(engine, dev_priv) {
|
||||
engine->buffer->head = engine->buffer->tail;
|
||||
engine->buffer->last_retired_head = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
|
||||
{
|
||||
int ret;
|
||||
@ -2223,13 +2241,12 @@ static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
|
||||
if (WARN_ON(&target->ring_link == &ring->request_list))
|
||||
return -ENOSPC;
|
||||
|
||||
ret = i915_wait_request(target, true, NULL, NO_WAITBOOST);
|
||||
ret = i915_wait_request(target,
|
||||
I915_WAIT_INTERRUPTIBLE | I915_WAIT_LOCKED,
|
||||
NULL, NO_WAITBOOST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (i915_reset_in_progress(&target->i915->gpu_error))
|
||||
return -EAGAIN;
|
||||
|
||||
i915_gem_request_retire_upto(target);
|
||||
|
||||
intel_ring_update_space(ring);
|
||||
@ -2655,6 +2672,7 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
|
||||
intel_ring_init_semaphores(dev_priv, engine);
|
||||
|
||||
engine->init_hw = init_ring_common;
|
||||
engine->reset_hw = reset_ring_common;
|
||||
|
||||
engine->emit_request = i9xx_emit_request;
|
||||
if (i915.semaphores)
|
||||
|
@ -87,7 +87,6 @@ struct intel_ring {
|
||||
void *vaddr;
|
||||
|
||||
struct intel_engine_cs *engine;
|
||||
struct list_head link;
|
||||
|
||||
struct list_head request_list;
|
||||
|
||||
@ -157,7 +156,6 @@ struct intel_engine_cs {
|
||||
u32 mmio_base;
|
||||
unsigned int irq_shift;
|
||||
struct intel_ring *buffer;
|
||||
struct list_head buffers;
|
||||
|
||||
/* Rather than have every client wait upon all user interrupts,
|
||||
* with the herd waking after every interrupt and each doing the
|
||||
@ -211,6 +209,8 @@ struct intel_engine_cs {
|
||||
void (*irq_disable)(struct intel_engine_cs *engine);
|
||||
|
||||
int (*init_hw)(struct intel_engine_cs *engine);
|
||||
void (*reset_hw)(struct intel_engine_cs *engine,
|
||||
struct drm_i915_gem_request *req);
|
||||
|
||||
int (*init_context)(struct drm_i915_gem_request *req);
|
||||
|
||||
@ -226,7 +226,15 @@ struct intel_engine_cs {
|
||||
#define I915_DISPATCH_PINNED BIT(1)
|
||||
#define I915_DISPATCH_RS BIT(2)
|
||||
int (*emit_request)(struct drm_i915_gem_request *req);
|
||||
|
||||
/* Pass the request to the hardware queue (e.g. directly into
|
||||
* the legacy ringbuffer or to the end of an execlist).
|
||||
*
|
||||
* This is called from an atomic context with irqs disabled; must
|
||||
* be irq safe.
|
||||
*/
|
||||
void (*submit_request)(struct drm_i915_gem_request *req);
|
||||
|
||||
/* Some chipsets are not quite as coherent as advertised and need
|
||||
* an expensive kick to force a true read of the up-to-date seqno.
|
||||
* However, the up-to-date seqno is not always required and the last
|
||||
@ -298,11 +306,14 @@ struct intel_engine_cs {
|
||||
/* Execlists */
|
||||
struct tasklet_struct irq_tasklet;
|
||||
spinlock_t execlist_lock; /* used inside tasklet, use spin_lock_bh */
|
||||
struct execlist_port {
|
||||
struct drm_i915_gem_request *request;
|
||||
unsigned int count;
|
||||
} execlist_port[2];
|
||||
struct list_head execlist_queue;
|
||||
unsigned int fw_domains;
|
||||
unsigned int next_context_status_buffer;
|
||||
unsigned int idle_lite_restore_wa;
|
||||
bool disable_lite_restore_wa;
|
||||
bool preempt_wa;
|
||||
u32 ctx_desc_template;
|
||||
|
||||
/**
|
||||
@ -441,6 +452,8 @@ void intel_ring_free(struct intel_ring *ring);
|
||||
void intel_engine_stop(struct intel_engine_cs *engine);
|
||||
void intel_engine_cleanup(struct intel_engine_cs *engine);
|
||||
|
||||
void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
|
||||
|
||||
int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request);
|
||||
|
||||
int __must_check intel_ring_begin(struct drm_i915_gem_request *req, int n);
|
||||
@ -479,6 +492,7 @@ int __intel_ring_space(int head, int tail, int size);
|
||||
void intel_ring_update_space(struct intel_ring *ring);
|
||||
|
||||
void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno);
|
||||
void intel_engine_reset_irq(struct intel_engine_cs *engine);
|
||||
|
||||
void intel_engine_setup_common(struct intel_engine_cs *engine);
|
||||
int intel_engine_init_common(struct intel_engine_cs *engine);
|
||||
@ -486,11 +500,11 @@ int intel_engine_create_scratch(struct intel_engine_cs *engine, int size);
|
||||
void intel_engine_cleanup_common(struct intel_engine_cs *engine);
|
||||
|
||||
static inline int intel_engine_idle(struct intel_engine_cs *engine,
|
||||
bool interruptible)
|
||||
unsigned int flags)
|
||||
{
|
||||
/* Wait upon the last request to be completed */
|
||||
return i915_gem_active_wait_unlocked(&engine->last_request,
|
||||
interruptible, NULL, NULL);
|
||||
flags, NULL, NULL);
|
||||
}
|
||||
|
||||
int intel_init_render_ring_buffer(struct intel_engine_cs *engine);
|
||||
|
@ -287,6 +287,7 @@ void intel_display_set_init_power(struct drm_i915_private *dev_priv,
|
||||
*/
|
||||
static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
|
||||
/*
|
||||
@ -299,9 +300,9 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
|
||||
* sure vgacon can keep working normally without triggering interrupts
|
||||
* and error messages.
|
||||
*/
|
||||
vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
|
||||
vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
|
||||
outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
|
||||
vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
|
||||
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
||||
|
||||
if (IS_BROADWELL(dev))
|
||||
gen8_irq_power_well_post_enable(dev_priv,
|
||||
@ -318,7 +319,7 @@ static void hsw_power_well_pre_disable(struct drm_i915_private *dev_priv)
|
||||
static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
|
||||
struct i915_power_well *power_well)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
|
||||
/*
|
||||
* After we re-enable the power well, if we touch VGA register 0x3d5
|
||||
@ -331,9 +332,9 @@ static void skl_power_well_post_enable(struct drm_i915_private *dev_priv,
|
||||
* and error messages.
|
||||
*/
|
||||
if (power_well->data == SKL_DISP_PW_2) {
|
||||
vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
|
||||
vga_get_uninterruptible(pdev, VGA_RSRC_LEGACY_IO);
|
||||
outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
|
||||
vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
|
||||
vga_put(pdev, VGA_RSRC_LEGACY_IO);
|
||||
|
||||
gen8_irq_power_well_post_enable(dev_priv,
|
||||
1 << PIPE_C | 1 << PIPE_B);
|
||||
@ -2288,7 +2289,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
void intel_power_domains_fini(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct device *device = &dev_priv->drm.pdev->dev;
|
||||
struct device *kdev = &dev_priv->drm.pdev->dev;
|
||||
|
||||
/*
|
||||
* The i915.ko module is still not prepared to be loaded when
|
||||
@ -2310,7 +2311,7 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
|
||||
* the platform doesn't support runtime PM.
|
||||
*/
|
||||
if (!HAS_RUNTIME_PM(dev_priv))
|
||||
pm_runtime_put(device);
|
||||
pm_runtime_put(kdev);
|
||||
}
|
||||
|
||||
static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv)
|
||||
@ -2651,10 +2652,10 @@ void intel_power_domains_suspend(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct device *kdev = &pdev->dev;
|
||||
|
||||
pm_runtime_get_sync(device);
|
||||
pm_runtime_get_sync(kdev);
|
||||
|
||||
atomic_inc(&dev_priv->pm.wakeref_count);
|
||||
assert_rpm_wakelock_held(dev_priv);
|
||||
@ -2672,11 +2673,11 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct device *kdev = &pdev->dev;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PM)) {
|
||||
int ret = pm_runtime_get_if_in_use(device);
|
||||
int ret = pm_runtime_get_if_in_use(kdev);
|
||||
|
||||
/*
|
||||
* In cases runtime PM is disabled by the RPM core and we get
|
||||
@ -2714,11 +2715,11 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct device *kdev = &pdev->dev;
|
||||
|
||||
assert_rpm_wakelock_held(dev_priv);
|
||||
pm_runtime_get_noresume(device);
|
||||
pm_runtime_get_noresume(kdev);
|
||||
|
||||
atomic_inc(&dev_priv->pm.wakeref_count);
|
||||
}
|
||||
@ -2733,15 +2734,15 @@ void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct device *kdev = &pdev->dev;
|
||||
|
||||
assert_rpm_wakelock_held(dev_priv);
|
||||
if (atomic_dec_and_test(&dev_priv->pm.wakeref_count))
|
||||
atomic_inc(&dev_priv->pm.atomic_seq);
|
||||
|
||||
pm_runtime_mark_last_busy(device);
|
||||
pm_runtime_put_autosuspend(device);
|
||||
pm_runtime_mark_last_busy(kdev);
|
||||
pm_runtime_put_autosuspend(kdev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2756,11 +2757,12 @@ void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
|
||||
*/
|
||||
void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
struct pci_dev *pdev = dev_priv->drm.pdev;
|
||||
struct drm_device *dev = &dev_priv->drm;
|
||||
struct device *device = &dev->pdev->dev;
|
||||
struct device *kdev = &pdev->dev;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
|
||||
pm_runtime_mark_last_busy(device);
|
||||
pm_runtime_set_autosuspend_delay(kdev, 10000); /* 10s */
|
||||
pm_runtime_mark_last_busy(kdev);
|
||||
|
||||
/*
|
||||
* Take a permanent reference to disable the RPM functionality and drop
|
||||
@ -2769,10 +2771,10 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
|
||||
* platforms without RPM support.
|
||||
*/
|
||||
if (!HAS_RUNTIME_PM(dev)) {
|
||||
pm_runtime_dont_use_autosuspend(device);
|
||||
pm_runtime_get_sync(device);
|
||||
pm_runtime_dont_use_autosuspend(kdev);
|
||||
pm_runtime_get_sync(kdev);
|
||||
} else {
|
||||
pm_runtime_use_autosuspend(device);
|
||||
pm_runtime_use_autosuspend(kdev);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2780,6 +2782,5 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
|
||||
* We drop that here and will reacquire it during unloading in
|
||||
* intel_power_domains_fini().
|
||||
*/
|
||||
pm_runtime_put_autosuspend(device);
|
||||
pm_runtime_put_autosuspend(kdev);
|
||||
}
|
||||
|
||||
|
@ -1003,24 +1003,22 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
}
|
||||
|
||||
static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
struct intel_crtc_state *pipe_config)
|
||||
{
|
||||
uint8_t sdvo_data[HDMI_INFOFRAME_SIZE(AVI)];
|
||||
struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
union hdmi_infoframe frame;
|
||||
int ret;
|
||||
ssize_t len;
|
||||
|
||||
ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
|
||||
adjusted_mode);
|
||||
&pipe_config->base.adjusted_mode);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("couldn't fill AVI infoframe\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intel_sdvo->rgb_quant_range_selectable) {
|
||||
if (intel_crtc->config->limited_color_range)
|
||||
if (pipe_config->limited_color_range)
|
||||
frame.avi.quantization_range =
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED;
|
||||
else
|
||||
@ -1125,7 +1123,8 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
|
||||
}
|
||||
|
||||
static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
|
||||
@ -1192,22 +1191,21 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
|
||||
static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
|
||||
struct intel_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = intel_encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
|
||||
struct drm_display_mode *mode = &crtc->config->base.mode;
|
||||
struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
|
||||
const struct drm_display_mode *adjusted_mode = &crtc_state->base.adjusted_mode;
|
||||
struct drm_display_mode *mode = &crtc_state->base.mode;
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
|
||||
u32 sdvox;
|
||||
struct intel_sdvo_in_out_map in_out;
|
||||
struct intel_sdvo_dtd input_dtd, output_dtd;
|
||||
int rate;
|
||||
|
||||
if (!mode)
|
||||
return;
|
||||
|
||||
/* First, set the input mapping for the first input to our controlled
|
||||
* output. This is only correct if we're a single-input device, in
|
||||
* which case the first input is the output from the appropriate SDVO
|
||||
@ -1240,11 +1238,11 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
|
||||
if (!intel_sdvo_set_target_input(intel_sdvo))
|
||||
return;
|
||||
|
||||
if (crtc->config->has_hdmi_sink) {
|
||||
if (crtc_state->has_hdmi_sink) {
|
||||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
|
||||
intel_sdvo_set_colorimetry(intel_sdvo,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode);
|
||||
intel_sdvo_set_avi_infoframe(intel_sdvo, crtc_state);
|
||||
} else
|
||||
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI);
|
||||
|
||||
@ -1260,7 +1258,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
|
||||
DRM_INFO("Setting input timings on %s failed\n",
|
||||
SDVO_NAME(intel_sdvo));
|
||||
|
||||
switch (crtc->config->pixel_multiplier) {
|
||||
switch (crtc_state->pixel_multiplier) {
|
||||
default:
|
||||
WARN(1, "unknown pixel multiplier specified\n");
|
||||
case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
|
||||
@ -1275,7 +1273,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
|
||||
/* The real mode polarity is set by the SDVO commands, using
|
||||
* struct intel_sdvo_dtd. */
|
||||
sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
|
||||
if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
|
||||
if (!HAS_PCH_SPLIT(dev) && crtc_state->limited_color_range)
|
||||
sdvox |= HDMI_COLOR_RANGE_16_235;
|
||||
if (INTEL_INFO(dev)->gen < 5)
|
||||
sdvox |= SDVO_BORDER_ENABLE;
|
||||
@ -1301,7 +1299,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
|
||||
} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
|
||||
/* done in crtc_mode_set as it lives inside the dpll register */
|
||||
} else {
|
||||
sdvox |= (crtc->config->pixel_multiplier - 1)
|
||||
sdvox |= (crtc_state->pixel_multiplier - 1)
|
||||
<< SDVO_PORT_MULTIPLY_SHIFT;
|
||||
}
|
||||
|
||||
@ -1434,7 +1432,9 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
|
||||
pipe_config->pixel_multiplier, encoder_pixel_multiplier);
|
||||
}
|
||||
|
||||
static void intel_disable_sdvo(struct intel_encoder *encoder)
|
||||
static void intel_disable_sdvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
|
||||
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
|
||||
@ -1477,16 +1477,22 @@ static void intel_disable_sdvo(struct intel_encoder *encoder)
|
||||
}
|
||||
}
|
||||
|
||||
static void pch_disable_sdvo(struct intel_encoder *encoder)
|
||||
static void pch_disable_sdvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
}
|
||||
|
||||
static void pch_post_disable_sdvo(struct intel_encoder *encoder)
|
||||
static void pch_post_disable_sdvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
intel_disable_sdvo(encoder);
|
||||
intel_disable_sdvo(encoder, old_crtc_state, old_conn_state);
|
||||
}
|
||||
|
||||
static void intel_enable_sdvo(struct intel_encoder *encoder)
|
||||
static void intel_enable_sdvo(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -2930,10 +2936,12 @@ static bool
|
||||
intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
|
||||
struct drm_device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = dev->pdev;
|
||||
|
||||
sdvo->ddc.owner = THIS_MODULE;
|
||||
sdvo->ddc.class = I2C_CLASS_DDC;
|
||||
snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
|
||||
sdvo->ddc.dev.parent = &dev->pdev->dev;
|
||||
sdvo->ddc.dev.parent = &pdev->dev;
|
||||
sdvo->ddc.algo_data = sdvo;
|
||||
sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
|
||||
|
||||
|
@ -203,6 +203,9 @@ skl_update_plane(struct drm_plane *drm_plane,
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
struct intel_plane *intel_plane = to_intel_plane(drm_plane);
|
||||
struct drm_framebuffer *fb = plane_state->base.fb;
|
||||
const struct skl_wm_values *wm = &dev_priv->wm.skl_results;
|
||||
struct drm_crtc *crtc = crtc_state->base.crtc;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
const int pipe = intel_plane->pipe;
|
||||
const int plane = intel_plane->plane + 1;
|
||||
u32 plane_ctl;
|
||||
@ -228,6 +231,9 @@ skl_update_plane(struct drm_plane *drm_plane,
|
||||
|
||||
plane_ctl |= skl_plane_ctl_rotation(rotation);
|
||||
|
||||
if (wm->dirty_pipes & drm_crtc_mask(crtc))
|
||||
skl_write_plane_wm(intel_crtc, wm, plane);
|
||||
|
||||
if (key->flags) {
|
||||
I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
|
||||
I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
|
||||
@ -286,6 +292,14 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
|
||||
const int pipe = intel_plane->pipe;
|
||||
const int plane = intel_plane->plane + 1;
|
||||
|
||||
/*
|
||||
* We only populate skl_results on watermark updates, and if the
|
||||
* plane's visiblity isn't actually changing neither is its watermarks.
|
||||
*/
|
||||
if (!dplane->state->visible)
|
||||
skl_write_plane_wm(to_intel_crtc(crtc),
|
||||
&dev_priv->wm.skl_results, plane);
|
||||
|
||||
I915_WRITE(PLANE_CTL(pipe, plane), 0);
|
||||
|
||||
I915_WRITE(PLANE_SURF(pipe, plane), 0);
|
||||
|
@ -838,7 +838,9 @@ intel_tv_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe)
|
||||
}
|
||||
|
||||
static void
|
||||
intel_enable_tv(struct intel_encoder *encoder)
|
||||
intel_enable_tv(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -851,7 +853,9 @@ intel_enable_tv(struct intel_encoder *encoder)
|
||||
}
|
||||
|
||||
static void
|
||||
intel_disable_tv(struct intel_encoder *encoder)
|
||||
intel_disable_tv(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *old_crtc_state,
|
||||
struct drm_connector_state *old_conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
@ -908,7 +912,8 @@ intel_tv_get_config(struct intel_encoder *encoder,
|
||||
|
||||
static bool
|
||||
intel_tv_compute_config(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config)
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct intel_tv *intel_tv = enc_to_tv(encoder);
|
||||
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
|
||||
@ -1010,7 +1015,9 @@ static void set_color_conversion(struct drm_i915_private *dev_priv,
|
||||
color_conversion->av);
|
||||
}
|
||||
|
||||
static void intel_tv_pre_enable(struct intel_encoder *encoder)
|
||||
static void intel_tv_pre_enable(struct intel_encoder *encoder,
|
||||
struct intel_crtc_state *pipe_config,
|
||||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct drm_device *dev = encoder->base.dev;
|
||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||
|
@ -1018,11 +1018,9 @@ gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool
|
||||
__gen5_write(8)
|
||||
__gen5_write(16)
|
||||
__gen5_write(32)
|
||||
__gen5_write(64)
|
||||
__gen2_write(8)
|
||||
__gen2_write(16)
|
||||
__gen2_write(32)
|
||||
__gen2_write(64)
|
||||
|
||||
#undef __gen5_write
|
||||
#undef __gen2_write
|
||||
@ -1112,23 +1110,18 @@ gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \
|
||||
__gen9_write(8)
|
||||
__gen9_write(16)
|
||||
__gen9_write(32)
|
||||
__gen9_write(64)
|
||||
__chv_write(8)
|
||||
__chv_write(16)
|
||||
__chv_write(32)
|
||||
__chv_write(64)
|
||||
__gen8_write(8)
|
||||
__gen8_write(16)
|
||||
__gen8_write(32)
|
||||
__gen8_write(64)
|
||||
__hsw_write(8)
|
||||
__hsw_write(16)
|
||||
__hsw_write(32)
|
||||
__hsw_write(64)
|
||||
__gen6_write(8)
|
||||
__gen6_write(16)
|
||||
__gen6_write(32)
|
||||
__gen6_write(64)
|
||||
|
||||
#undef __gen9_write
|
||||
#undef __chv_write
|
||||
@ -1158,7 +1151,6 @@ static void vgpu_write##x(struct drm_i915_private *dev_priv, \
|
||||
__vgpu_write(8)
|
||||
__vgpu_write(16)
|
||||
__vgpu_write(32)
|
||||
__vgpu_write(64)
|
||||
|
||||
#undef __vgpu_write
|
||||
#undef VGPU_WRITE_FOOTER
|
||||
@ -1169,7 +1161,6 @@ do { \
|
||||
dev_priv->uncore.funcs.mmio_writeb = x##_write8; \
|
||||
dev_priv->uncore.funcs.mmio_writew = x##_write16; \
|
||||
dev_priv->uncore.funcs.mmio_writel = x##_write32; \
|
||||
dev_priv->uncore.funcs.mmio_writeq = x##_write64; \
|
||||
} while (0)
|
||||
|
||||
#define ASSIGN_READ_MMIO_VFUNCS(x) \
|
||||
@ -1597,8 +1588,10 @@ static int gen6_reset_engines(struct drm_i915_private *dev_priv,
|
||||
if (engine_mask == ALL_ENGINES) {
|
||||
hw_mask = GEN6_GRDOM_FULL;
|
||||
} else {
|
||||
unsigned int tmp;
|
||||
|
||||
hw_mask = 0;
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask)
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
|
||||
hw_mask |= hw_engine_mask[engine->id];
|
||||
}
|
||||
|
||||
@ -1714,15 +1707,16 @@ static int gen8_reset_engines(struct drm_i915_private *dev_priv,
|
||||
unsigned engine_mask)
|
||||
{
|
||||
struct intel_engine_cs *engine;
|
||||
unsigned int tmp;
|
||||
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask)
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
|
||||
if (gen8_request_engine_reset(engine))
|
||||
goto not_ready;
|
||||
|
||||
return gen6_reset_engines(dev_priv, engine_mask);
|
||||
|
||||
not_ready:
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask)
|
||||
for_each_engine_masked(engine, dev_priv, engine_mask, tmp)
|
||||
gen8_unrequest_engine_reset(engine);
|
||||
|
||||
return -EIO;
|
||||
|
@ -168,6 +168,26 @@ void drm_printk(const char *level, unsigned int category,
|
||||
/** \name Macros to make printk easier */
|
||||
/*@{*/
|
||||
|
||||
#define _DRM_PRINTK(once, level, fmt, ...) \
|
||||
do { \
|
||||
printk##once(KERN_##level "[" DRM_NAME "] " fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DRM_INFO(fmt, ...) \
|
||||
_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
|
||||
#define DRM_NOTE(fmt, ...) \
|
||||
_DRM_PRINTK(, NOTICE, fmt, ##__VA_ARGS__)
|
||||
#define DRM_WARN(fmt, ...) \
|
||||
_DRM_PRINTK(, WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define DRM_INFO_ONCE(fmt, ...) \
|
||||
_DRM_PRINTK(_once, INFO, fmt, ##__VA_ARGS__)
|
||||
#define DRM_NOTE_ONCE(fmt, ...) \
|
||||
_DRM_PRINTK(_once, NOTICE, fmt, ##__VA_ARGS__)
|
||||
#define DRM_WARN_ONCE(fmt, ...) \
|
||||
_DRM_PRINTK(_once, WARNING, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Error output.
|
||||
*
|
||||
@ -202,8 +222,6 @@ void drm_printk(const char *level, unsigned int category,
|
||||
#define DRM_DEV_INFO(dev, fmt, ...) \
|
||||
drm_dev_printk(dev, KERN_INFO, DRM_UT_NONE, __func__, "", fmt, \
|
||||
##__VA_ARGS__)
|
||||
#define DRM_INFO(fmt, ...) \
|
||||
drm_printk(KERN_INFO, DRM_UT_NONE, __func__, "", fmt, ##__VA_ARGS__)
|
||||
|
||||
#define DRM_DEV_INFO_ONCE(dev, fmt, ...) \
|
||||
({ \
|
||||
@ -213,7 +231,6 @@ void drm_printk(const char *level, unsigned int category,
|
||||
DRM_DEV_INFO(dev, fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
})
|
||||
#define DRM_INFO_ONCE(fmt, ...) DRM_DEV_INFO_ONCE(NULL, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Debug output.
|
||||
|
@ -211,14 +211,16 @@
|
||||
# define DP_DS_PORT_TYPE_DVI 2
|
||||
# define DP_DS_PORT_TYPE_HDMI 3
|
||||
# define DP_DS_PORT_TYPE_NON_EDID 4
|
||||
# define DP_DS_PORT_TYPE_DP_DUALMODE 5
|
||||
# define DP_DS_PORT_TYPE_WIRELESS 6
|
||||
# define DP_DS_PORT_HPD (1 << 3)
|
||||
/* offset 1 for VGA is maximum megapixels per second / 8 */
|
||||
/* offset 2 */
|
||||
# define DP_DS_VGA_MAX_BPC_MASK (3 << 0)
|
||||
# define DP_DS_VGA_8BPC 0
|
||||
# define DP_DS_VGA_10BPC 1
|
||||
# define DP_DS_VGA_12BPC 2
|
||||
# define DP_DS_VGA_16BPC 3
|
||||
# define DP_DS_MAX_BPC_MASK (3 << 0)
|
||||
# define DP_DS_8BPC 0
|
||||
# define DP_DS_10BPC 1
|
||||
# define DP_DS_12BPC 2
|
||||
# define DP_DS_16BPC 3
|
||||
|
||||
/* link configuration */
|
||||
#define DP_LINK_BW_SET 0x100
|
||||
@ -443,6 +445,9 @@
|
||||
#define DP_SOURCE_OUI 0x300
|
||||
#define DP_SINK_OUI 0x400
|
||||
#define DP_BRANCH_OUI 0x500
|
||||
#define DP_BRANCH_ID 0x503
|
||||
#define DP_BRANCH_HW_REV 0x509
|
||||
#define DP_BRANCH_SW_REV 0x50A
|
||||
|
||||
#define DP_SET_POWER 0x600
|
||||
# define DP_SET_POWER_D0 0x1
|
||||
@ -813,6 +818,13 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
|
||||
int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
|
||||
int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);
|
||||
int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
|
||||
int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4]);
|
||||
int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]);
|
||||
void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE],
|
||||
const u8 port_cap[4], struct drm_dp_aux *aux);
|
||||
|
||||
void drm_dp_aux_init(struct drm_dp_aux *aux);
|
||||
int drm_dp_aux_register(struct drm_dp_aux *aux);
|
||||
|
@ -134,7 +134,7 @@
|
||||
#define INTEL_IVB_Q_IDS(info) \
|
||||
INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
|
||||
|
||||
#define INTEL_HSW_D_IDS(info) \
|
||||
#define INTEL_HSW_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
|
||||
INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
|
||||
INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
|
||||
@ -179,9 +179,7 @@
|
||||
INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
|
||||
INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
|
||||
INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
|
||||
INTEL_VGA_DEVICE(0x0D2E, info) /* CRW GT3 reserved */ \
|
||||
|
||||
#define INTEL_HSW_M_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x0D2E, info), /* CRW GT3 reserved */ \
|
||||
INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
|
||||
INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
|
||||
INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
|
||||
@ -198,17 +196,15 @@
|
||||
INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
|
||||
INTEL_VGA_DEVICE(0x0D26, info) /* CRW GT3 mobile */
|
||||
|
||||
#define INTEL_VLV_M_IDS(info) \
|
||||
#define INTEL_VLV_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x0f30, info), \
|
||||
INTEL_VGA_DEVICE(0x0f31, info), \
|
||||
INTEL_VGA_DEVICE(0x0f32, info), \
|
||||
INTEL_VGA_DEVICE(0x0f33, info), \
|
||||
INTEL_VGA_DEVICE(0x0157, info)
|
||||
|
||||
#define INTEL_VLV_D_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x0157, info), \
|
||||
INTEL_VGA_DEVICE(0x0155, info)
|
||||
|
||||
#define INTEL_BDW_GT12M_IDS(info) \
|
||||
#define INTEL_BDW_GT12_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
|
||||
INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
|
||||
INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
|
||||
@ -216,21 +212,17 @@
|
||||
INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
|
||||
INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
|
||||
INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
|
||||
INTEL_VGA_DEVICE(0x161E, info) /* GT2 ULX */
|
||||
|
||||
#define INTEL_BDW_GT12D_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x161E, info), /* GT2 ULX */ \
|
||||
INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
|
||||
INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
|
||||
INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
|
||||
INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */
|
||||
|
||||
#define INTEL_BDW_GT3M_IDS(info) \
|
||||
#define INTEL_BDW_GT3_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
|
||||
INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
|
||||
INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
|
||||
INTEL_VGA_DEVICE(0x162E, info) /* ULX */
|
||||
|
||||
#define INTEL_BDW_GT3D_IDS(info) \
|
||||
INTEL_VGA_DEVICE(0x162E, info), /* ULX */\
|
||||
INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
|
||||
INTEL_VGA_DEVICE(0x162D, info) /* Workstation */
|
||||
|
||||
@ -244,14 +236,12 @@
|
||||
INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
|
||||
INTEL_VGA_DEVICE(0x163D, info) /* Workstation */
|
||||
|
||||
#define INTEL_BDW_M_IDS(info) \
|
||||
INTEL_BDW_GT12M_IDS(info), \
|
||||
INTEL_BDW_GT3M_IDS(info), \
|
||||
INTEL_BDW_RSVDM_IDS(info)
|
||||
|
||||
#define INTEL_BDW_D_IDS(info) \
|
||||
INTEL_BDW_GT12D_IDS(info), \
|
||||
INTEL_BDW_GT3D_IDS(info), \
|
||||
#define INTEL_BDW_IDS(info) \
|
||||
INTEL_BDW_GT12_IDS(info), \
|
||||
INTEL_BDW_GT3_IDS(info), \
|
||||
INTEL_BDW_RSVDM_IDS(info), \
|
||||
INTEL_BDW_GT12_IDS(info), \
|
||||
INTEL_BDW_GT3_IDS(info), \
|
||||
INTEL_BDW_RSVDD_IDS(info)
|
||||
|
||||
#define INTEL_CHV_IDS(info) \
|
||||
|
@ -387,6 +387,7 @@ typedef struct drm_i915_irq_wait {
|
||||
#define I915_PARAM_HAS_EXEC_SOFTPIN 37
|
||||
#define I915_PARAM_HAS_POOLED_EU 38
|
||||
#define I915_PARAM_MIN_EU_IN_POOL 39
|
||||
#define I915_PARAM_MMAP_GTT_VERSION 40
|
||||
|
||||
typedef struct drm_i915_getparam {
|
||||
__s32 param;
|
||||
|
Loading…
Reference in New Issue
Block a user