Merge remote branch 'anholt/drm-intel-next' into drm-next-stage
* anholt/drm-intel-next: drm/i915: Record batch buffer following GPU error drm/i915: give up on 8xx lid status drm/i915: reduce some of the duplication of tiling checking drm/i915: blow away userspace mappings before fence change drm/i915: move a gtt flush to the correct place agp/intel: official names for Pineview and Ironlake drm/i915: overlay: drop superflous gpu flushes drm/i915: overlay: nuke readback to flush wc caches drm/i915: provide self-refresh status in debugfs drm/i915: provide FBC status in debugfs drm/i915: fix drps disable so unload & re-load works drm/i915: Fix OGLC performance regression on 945 drm/i915: Deobfuscate the render p-state obfuscation drm/i915: add dynamic performance control support for Ironlake drm/i915: enable memory self refresh on 9xx drm/i915: Don't reserve compatibility fence regs in KMS mode. drm/i915: Keep MCHBAR always enabled drm/i915: Replace open-coded eviction in i915_gem_idle()
This commit is contained in:
commit
30d6c72c4a
|
@ -2345,9 +2345,9 @@ static const struct intel_driver_description {
|
|||
NULL, &intel_g33_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
|
||||
NULL, &intel_g33_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "Pineview",
|
||||
{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
|
||||
NULL, &intel_g33_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "Pineview",
|
||||
{ PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
|
||||
NULL, &intel_g33_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
|
||||
"GM45", NULL, &intel_i965_driver },
|
||||
|
@ -2362,13 +2362,13 @@ static const struct intel_driver_description {
|
|||
{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
|
||||
"G41", NULL, &intel_i965_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
|
||||
"Ironlake/D", NULL, &intel_i965_driver },
|
||||
"HD Graphics", NULL, &intel_i965_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
|
||||
"Ironlake/M", NULL, &intel_i965_driver },
|
||||
"HD Graphics", NULL, &intel_i965_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
|
||||
"Ironlake/MA", NULL, &intel_i965_driver },
|
||||
"HD Graphics", NULL, &intel_i965_driver },
|
||||
{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
|
||||
"Ironlake/MC2", NULL, &intel_i965_driver },
|
||||
"HD Graphics", NULL, &intel_i965_driver },
|
||||
{ 0, 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
|
|
@ -350,6 +350,36 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *pin_flag(int pinned)
|
||||
{
|
||||
if (pinned > 0)
|
||||
return " P";
|
||||
else if (pinned < 0)
|
||||
return " p";
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
static const char *tiling_flag(int tiling)
|
||||
{
|
||||
switch (tiling) {
|
||||
default:
|
||||
case I915_TILING_NONE: return "";
|
||||
case I915_TILING_X: return " X";
|
||||
case I915_TILING_Y: return " Y";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *dirty_flag(int dirty)
|
||||
{
|
||||
return dirty ? " dirty" : "";
|
||||
}
|
||||
|
||||
static const char *purgeable_flag(int purgeable)
|
||||
{
|
||||
return purgeable ? " purgeable" : "";
|
||||
}
|
||||
|
||||
static int i915_error_state(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
|
@ -357,6 +387,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_error_state *error;
|
||||
unsigned long flags;
|
||||
int i, page, offset, elt;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
if (!dev_priv->first_error) {
|
||||
|
@ -368,6 +399,7 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
|
||||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||||
error->time.tv_usec);
|
||||
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
|
||||
seq_printf(m, "EIR: 0x%08x\n", error->eir);
|
||||
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
|
||||
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
|
||||
|
@ -379,6 +411,59 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
|
||||
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
|
||||
}
|
||||
seq_printf(m, "seqno: 0x%08x\n", error->seqno);
|
||||
|
||||
if (error->active_bo_count) {
|
||||
seq_printf(m, "Buffers [%d]:\n", error->active_bo_count);
|
||||
|
||||
for (i = 0; i < error->active_bo_count; i++) {
|
||||
seq_printf(m, " %08x %8zd %08x %08x %08x%s%s%s%s",
|
||||
error->active_bo[i].gtt_offset,
|
||||
error->active_bo[i].size,
|
||||
error->active_bo[i].read_domains,
|
||||
error->active_bo[i].write_domain,
|
||||
error->active_bo[i].seqno,
|
||||
pin_flag(error->active_bo[i].pinned),
|
||||
tiling_flag(error->active_bo[i].tiling),
|
||||
dirty_flag(error->active_bo[i].dirty),
|
||||
purgeable_flag(error->active_bo[i].purgeable));
|
||||
|
||||
if (error->active_bo[i].name)
|
||||
seq_printf(m, " (name: %d)", error->active_bo[i].name);
|
||||
if (error->active_bo[i].fence_reg != I915_FENCE_REG_NONE)
|
||||
seq_printf(m, " (fence: %d)", error->active_bo[i].fence_reg);
|
||||
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(error->batchbuffer); i++) {
|
||||
if (error->batchbuffer[i]) {
|
||||
struct drm_i915_error_object *obj = error->batchbuffer[i];
|
||||
|
||||
seq_printf(m, "--- gtt_offset = 0x%08x\n", obj->gtt_offset);
|
||||
offset = 0;
|
||||
for (page = 0; page < obj->page_count; page++) {
|
||||
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
|
||||
seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error->ringbuffer) {
|
||||
struct drm_i915_error_object *obj = error->ringbuffer;
|
||||
|
||||
seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset);
|
||||
offset = 0;
|
||||
for (page = 0; page < obj->page_count; page++) {
|
||||
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
|
||||
seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
|
@ -386,6 +471,165 @@ out:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int i915_rstdby_delays(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u16 crstanddelay = I915_READ16(CRSTANDVID);
|
||||
|
||||
seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_cur_delayinfo(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u16 rgvswctl = I915_READ16(MEMSWCTL);
|
||||
|
||||
seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
|
||||
seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
|
||||
seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
|
||||
rgvswctl & 0x3f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_delayfreq_table(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 delayfreq;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
|
||||
seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int MAP_TO_MV(int map)
|
||||
{
|
||||
return 1250 - (map * 25);
|
||||
}
|
||||
|
||||
static int i915_inttoext_table(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 inttoext;
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= 32; i++) {
|
||||
inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
|
||||
seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_drpc_info(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 rgvmodectl = I915_READ(MEMMODECTL);
|
||||
|
||||
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
|
||||
"yes" : "no");
|
||||
seq_printf(m, "Boost freq: %d\n",
|
||||
(rgvmodectl & MEMMODE_BOOST_FREQ_MASK) >>
|
||||
MEMMODE_BOOST_FREQ_SHIFT);
|
||||
seq_printf(m, "HW control enabled: %s\n",
|
||||
rgvmodectl & MEMMODE_HWIDLE_EN ? "yes" : "no");
|
||||
seq_printf(m, "SW control enabled: %s\n",
|
||||
rgvmodectl & MEMMODE_SWMODE_EN ? "yes" : "no");
|
||||
seq_printf(m, "Gated voltage change: %s\n",
|
||||
rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
|
||||
seq_printf(m, "Starting frequency: P%d\n",
|
||||
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
|
||||
seq_printf(m, "Max frequency: P%d\n",
|
||||
(rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
|
||||
seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_fbc_status(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
struct drm_crtc *crtc;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
bool fbc_enabled = false;
|
||||
|
||||
if (!dev_priv->display.fbc_enabled) {
|
||||
seq_printf(m, "FBC unsupported on this chipset\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
if (dev_priv->display.fbc_enabled(crtc))
|
||||
fbc_enabled = true;
|
||||
}
|
||||
|
||||
if (fbc_enabled) {
|
||||
seq_printf(m, "FBC enabled\n");
|
||||
} else {
|
||||
seq_printf(m, "FBC disabled: ");
|
||||
switch (dev_priv->no_fbc_reason) {
|
||||
case FBC_STOLEN_TOO_SMALL:
|
||||
seq_printf(m, "not enough stolen memory");
|
||||
break;
|
||||
case FBC_UNSUPPORTED_MODE:
|
||||
seq_printf(m, "mode not supported");
|
||||
break;
|
||||
case FBC_MODE_TOO_LARGE:
|
||||
seq_printf(m, "mode too large");
|
||||
break;
|
||||
case FBC_BAD_PLANE:
|
||||
seq_printf(m, "FBC unsupported on plane");
|
||||
break;
|
||||
case FBC_NOT_TILED:
|
||||
seq_printf(m, "scanout buffer not tiled");
|
||||
break;
|
||||
default:
|
||||
seq_printf(m, "unknown reason");
|
||||
}
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i915_sr_status(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct drm_info_node *node = (struct drm_info_node *) m->private;
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
bool sr_enabled = false;
|
||||
|
||||
if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev))
|
||||
sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
|
||||
else if (IS_I915GM(dev))
|
||||
sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
|
||||
else if (IS_PINEVIEW(dev))
|
||||
sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
|
||||
|
||||
seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
|
||||
"disabled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_wedged_open(struct inode *inode,
|
||||
struct file *filp)
|
||||
|
@ -503,6 +747,13 @@ static struct drm_info_list i915_debugfs_list[] = {
|
|||
{"i915_ringbuffer_info", i915_ringbuffer_info, 0},
|
||||
{"i915_batchbuffers", i915_batchbuffer_info, 0},
|
||||
{"i915_error_state", i915_error_state, 0},
|
||||
{"i915_rstdby_delays", i915_rstdby_delays, 0},
|
||||
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
|
||||
{"i915_delayfreq_table", i915_delayfreq_table, 0},
|
||||
{"i915_inttoext_table", i915_inttoext_table, 0},
|
||||
{"i915_drpc_info", i915_drpc_info, 0},
|
||||
{"i915_fbc_status", i915_fbc_status, 0},
|
||||
{"i915_sr_status", i915_sr_status, 0},
|
||||
};
|
||||
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "i915_drv.h"
|
||||
#include "i915_trace.h"
|
||||
#include <linux/vgaarb.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pnp.h>
|
||||
|
||||
/* Really want an OS-independent resettable timer. Would like to have
|
||||
* this loop run for (eg) 3 sec, but have the timer reset every time
|
||||
|
@ -933,6 +935,120 @@ static int i915_get_bridge_dev(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define MCHBAR_I915 0x44
|
||||
#define MCHBAR_I965 0x48
|
||||
#define MCHBAR_SIZE (4*4096)
|
||||
|
||||
#define DEVEN_REG 0x54
|
||||
#define DEVEN_MCHBAR_EN (1 << 28)
|
||||
|
||||
/* Allocate space for the MCH regs if needed, return nonzero on error */
|
||||
static int
|
||||
intel_alloc_mchbar_resource(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp_lo, temp_hi = 0;
|
||||
u64 mchbar_addr;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_I965G(dev))
|
||||
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
|
||||
pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
|
||||
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
|
||||
|
||||
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
|
||||
#ifdef CONFIG_PNP
|
||||
if (mchbar_addr &&
|
||||
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get some space for it */
|
||||
ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
|
||||
MCHBAR_SIZE, MCHBAR_SIZE,
|
||||
PCIBIOS_MIN_MEM,
|
||||
0, pcibios_align_resource,
|
||||
dev_priv->bridge_dev);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
|
||||
dev_priv->mch_res.start = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_I965G(dev))
|
||||
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
|
||||
upper_32_bits(dev_priv->mch_res.start));
|
||||
|
||||
pci_write_config_dword(dev_priv->bridge_dev, reg,
|
||||
lower_32_bits(dev_priv->mch_res.start));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup MCHBAR if possible, return true if we should disable it again */
|
||||
static void
|
||||
intel_setup_mchbar(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp;
|
||||
bool enabled;
|
||||
|
||||
dev_priv->mchbar_need_disable = false;
|
||||
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
|
||||
enabled = !!(temp & DEVEN_MCHBAR_EN);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
enabled = temp & 1;
|
||||
}
|
||||
|
||||
/* If it's already enabled, don't have to do anything */
|
||||
if (enabled)
|
||||
return;
|
||||
|
||||
if (intel_alloc_mchbar_resource(dev))
|
||||
return;
|
||||
|
||||
dev_priv->mchbar_need_disable = true;
|
||||
|
||||
/* Space is allocated or reserved, so enable it. */
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
|
||||
temp | DEVEN_MCHBAR_EN);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
intel_teardown_mchbar(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp;
|
||||
|
||||
if (dev_priv->mchbar_need_disable) {
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
|
||||
temp &= ~DEVEN_MCHBAR_EN;
|
||||
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
temp &= ~1;
|
||||
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
|
||||
}
|
||||
}
|
||||
|
||||
if (dev_priv->mch_res.start)
|
||||
release_resource(&dev_priv->mch_res);
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_probe_agp - get AGP bootup configuration
|
||||
* @pdev: PCI device
|
||||
|
@ -1133,6 +1249,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
|||
/* Leave 1M for line length buffer & misc. */
|
||||
compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
|
||||
if (!compressed_fb) {
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
i915_warn_stolen(dev);
|
||||
return;
|
||||
}
|
||||
|
@ -1140,6 +1257,7 @@ static void i915_setup_compression(struct drm_device *dev, int size)
|
|||
compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
|
||||
if (!compressed_fb) {
|
||||
i915_warn_stolen(dev);
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1450,6 +1568,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
|
||||
}
|
||||
|
||||
/* Try to make sure MCHBAR is enabled before poking at it */
|
||||
intel_setup_mchbar(dev);
|
||||
|
||||
i915_gem_load(dev);
|
||||
|
||||
/* Init HWS */
|
||||
|
@ -1523,6 +1644,8 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
i915_destroy_error_state(dev);
|
||||
|
||||
destroy_workqueue(dev_priv->wq);
|
||||
del_timer_sync(&dev_priv->hangcheck_timer);
|
||||
|
||||
|
@ -1569,6 +1692,8 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
intel_cleanup_overlay(dev);
|
||||
}
|
||||
|
||||
intel_teardown_mchbar(dev);
|
||||
|
||||
pci_dev_put(dev_priv->bridge_dev);
|
||||
kfree(dev->dev_private);
|
||||
|
||||
|
|
|
@ -571,6 +571,11 @@ static int __init i915_init(void)
|
|||
driver.driver_features &= ~DRIVER_MODESET;
|
||||
#endif
|
||||
|
||||
if (!(driver.driver_features & DRIVER_MODESET)) {
|
||||
driver.suspend = i915_suspend;
|
||||
driver.resume = i915_resume;
|
||||
}
|
||||
|
||||
return drm_init(&driver);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,27 @@ struct drm_i915_error_state {
|
|||
u32 instps;
|
||||
u32 instdone1;
|
||||
u32 seqno;
|
||||
u64 bbaddr;
|
||||
struct timeval time;
|
||||
struct drm_i915_error_object {
|
||||
int page_count;
|
||||
u32 gtt_offset;
|
||||
u32 *pages[0];
|
||||
} *ringbuffer, *batchbuffer[2];
|
||||
struct drm_i915_error_buffer {
|
||||
size_t size;
|
||||
u32 name;
|
||||
u32 seqno;
|
||||
u32 gtt_offset;
|
||||
u32 read_domains;
|
||||
u32 write_domain;
|
||||
u32 fence_reg;
|
||||
s32 pinned:2;
|
||||
u32 tiling:2;
|
||||
u32 dirty:1;
|
||||
u32 purgeable:1;
|
||||
} *active_bo;
|
||||
u32 active_bo_count;
|
||||
};
|
||||
|
||||
struct drm_i915_display_funcs {
|
||||
|
@ -192,6 +212,14 @@ struct intel_device_info {
|
|||
u8 cursor_needs_physical : 1;
|
||||
};
|
||||
|
||||
enum no_fbc_reason {
|
||||
FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
|
||||
FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
|
||||
FBC_MODE_TOO_LARGE, /* mode too large for compression */
|
||||
FBC_BAD_PLANE, /* fbc not supported on plane */
|
||||
FBC_NOT_TILED, /* buffer not tiled */
|
||||
};
|
||||
|
||||
typedef struct drm_i915_private {
|
||||
struct drm_device *dev;
|
||||
|
||||
|
@ -452,6 +480,7 @@ typedef struct drm_i915_private {
|
|||
u32 savePIPEB_DATA_N1;
|
||||
u32 savePIPEB_LINK_M1;
|
||||
u32 savePIPEB_LINK_N1;
|
||||
u32 saveMCHBAR_RENDER_STANDBY;
|
||||
|
||||
struct {
|
||||
struct drm_mm gtt_space;
|
||||
|
@ -590,6 +619,14 @@ typedef struct drm_i915_private {
|
|||
int child_dev_num;
|
||||
struct child_device_config *child_dev;
|
||||
struct drm_connector *int_lvds_connector;
|
||||
|
||||
bool mchbar_need_disable;
|
||||
|
||||
u8 cur_delay;
|
||||
u8 min_delay;
|
||||
u8 max_delay;
|
||||
|
||||
enum no_fbc_reason no_fbc_reason;
|
||||
} drm_i915_private_t;
|
||||
|
||||
/** driver private structure attached to each drm_gem_object */
|
||||
|
@ -761,6 +798,7 @@ extern int i965_reset(struct drm_device *dev, u8 flags);
|
|||
|
||||
/* i915_irq.c */
|
||||
void i915_hangcheck_elapsed(unsigned long data);
|
||||
void i915_destroy_error_state(struct drm_device *dev);
|
||||
extern int i915_irq_emit(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv);
|
||||
extern int i915_irq_wait(struct drm_device *dev, void *data,
|
||||
|
@ -897,7 +935,8 @@ void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
|
|||
void i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj);
|
||||
bool i915_tiling_ok(struct drm_device *dev, int stride, int size,
|
||||
int tiling_mode);
|
||||
bool i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj);
|
||||
bool i915_gem_object_fence_offset_ok(struct drm_gem_object *obj,
|
||||
int tiling_mode);
|
||||
|
||||
/* i915_gem_debug.c */
|
||||
void i915_gem_dump_object(struct drm_gem_object *obj, int len,
|
||||
|
|
|
@ -2540,6 +2540,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
|
|||
if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
|
||||
return 0;
|
||||
|
||||
/* If we've changed tiling, GTT-mappings of the object
|
||||
* need to re-fault to ensure that the correct fence register
|
||||
* setup is in place.
|
||||
*/
|
||||
i915_gem_release_mmap(obj);
|
||||
|
||||
/* On the i915, GPU access to tiled buffers is via a fence,
|
||||
* therefore we must wait for any outstanding access to complete
|
||||
* before clearing the fence.
|
||||
|
@ -2548,12 +2554,12 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
|
|||
int ret;
|
||||
|
||||
i915_gem_object_flush_gpu_write_domain(obj);
|
||||
i915_gem_object_flush_gtt_write_domain(obj);
|
||||
ret = i915_gem_object_wait_rendering(obj);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
i915_gem_object_flush_gtt_write_domain(obj);
|
||||
i915_gem_clear_fence_reg (obj);
|
||||
|
||||
return 0;
|
||||
|
@ -3243,7 +3249,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
|
|||
obj_priv->tiling_mode != I915_TILING_NONE;
|
||||
|
||||
/* Check fence reg constraints and rebind if necessary */
|
||||
if (need_fence && !i915_obj_fenceable(dev, obj))
|
||||
if (need_fence && !i915_gem_object_fence_offset_ok(obj,
|
||||
obj_priv->tiling_mode))
|
||||
i915_gem_object_unbind(obj);
|
||||
|
||||
/* Choose the GTT offset for our buffer and put it there. */
|
||||
|
@ -4437,12 +4444,35 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
i915_gpu_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
bool lists_empty;
|
||||
uint32_t seqno;
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
|
||||
list_empty(&dev_priv->mm.active_list);
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
if (lists_empty)
|
||||
return 0;
|
||||
|
||||
/* Flush everything onto the inactive list. */
|
||||
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
||||
seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
|
||||
if (seqno == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return i915_wait_request(dev, seqno);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t seqno, cur_seqno, last_seqno;
|
||||
int stuck, ret;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
|
@ -4451,115 +4481,36 @@ i915_gem_idle(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Hack! Don't let anybody do execbuf while we don't control the chip.
|
||||
* We need to replace this with a semaphore, or something.
|
||||
*/
|
||||
dev_priv->mm.suspended = 1;
|
||||
del_timer(&dev_priv->hangcheck_timer);
|
||||
|
||||
/* Cancel the retire work handler, wait for it to finish if running
|
||||
*/
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
i915_kernel_lost_context(dev);
|
||||
|
||||
/* Flush the GPU along with all non-CPU write domains
|
||||
*/
|
||||
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
|
||||
seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
|
||||
|
||||
if (seqno == 0) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_priv->mm.waiting_gem_seqno = seqno;
|
||||
last_seqno = 0;
|
||||
stuck = 0;
|
||||
for (;;) {
|
||||
cur_seqno = i915_get_gem_seqno(dev);
|
||||
if (i915_seqno_passed(cur_seqno, seqno))
|
||||
break;
|
||||
if (last_seqno == cur_seqno) {
|
||||
if (stuck++ > 100) {
|
||||
DRM_ERROR("hardware wedged\n");
|
||||
atomic_set(&dev_priv->mm.wedged, 1);
|
||||
DRM_WAKEUP(&dev_priv->irq_queue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
msleep(10);
|
||||
last_seqno = cur_seqno;
|
||||
}
|
||||
dev_priv->mm.waiting_gem_seqno = 0;
|
||||
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
if (!atomic_read(&dev_priv->mm.wedged)) {
|
||||
/* Active and flushing should now be empty as we've
|
||||
* waited for a sequence higher than any pending execbuffer
|
||||
*/
|
||||
WARN_ON(!list_empty(&dev_priv->mm.active_list));
|
||||
WARN_ON(!list_empty(&dev_priv->mm.flushing_list));
|
||||
/* Request should now be empty as we've also waited
|
||||
* for the last request in the list
|
||||
*/
|
||||
WARN_ON(!list_empty(&dev_priv->mm.request_list));
|
||||
}
|
||||
|
||||
/* Empty the active and flushing lists to inactive. If there's
|
||||
* anything left at this point, it means that we're wedged and
|
||||
* nothing good's going to happen by leaving them there. So strip
|
||||
* the GPU domains and just stuff them onto inactive.
|
||||
*/
|
||||
while (!list_empty(&dev_priv->mm.active_list)) {
|
||||
struct drm_gem_object *obj;
|
||||
uint32_t old_write_domain;
|
||||
|
||||
obj = list_first_entry(&dev_priv->mm.active_list,
|
||||
struct drm_i915_gem_object,
|
||||
list)->obj;
|
||||
old_write_domain = obj->write_domain;
|
||||
obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
|
||||
i915_gem_object_move_to_inactive(obj);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
obj->read_domains,
|
||||
old_write_domain);
|
||||
}
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
while (!list_empty(&dev_priv->mm.flushing_list)) {
|
||||
struct drm_gem_object *obj;
|
||||
uint32_t old_write_domain;
|
||||
|
||||
obj = list_first_entry(&dev_priv->mm.flushing_list,
|
||||
struct drm_i915_gem_object,
|
||||
list)->obj;
|
||||
old_write_domain = obj->write_domain;
|
||||
obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
|
||||
i915_gem_object_move_to_inactive(obj);
|
||||
|
||||
trace_i915_gem_object_change_domain(obj,
|
||||
obj->read_domains,
|
||||
old_write_domain);
|
||||
}
|
||||
|
||||
|
||||
/* Move all inactive buffers out of the GTT. */
|
||||
ret = i915_gem_evict_from_inactive_list(dev);
|
||||
WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
|
||||
ret = i915_gpu_idle(dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Under UMS, be paranoid and evict. */
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
ret = i915_gem_evict_from_inactive_list(dev);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hack! Don't let anybody do execbuf while we don't control the chip.
|
||||
* We need to replace this with a semaphore, or something.
|
||||
* And not confound mm.suspended!
|
||||
*/
|
||||
dev_priv->mm.suspended = 1;
|
||||
del_timer(&dev_priv->hangcheck_timer);
|
||||
|
||||
i915_kernel_lost_context(dev);
|
||||
i915_gem_cleanup_ringbuffer(dev);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
/* Cancel the retire work handler, which should be idle now. */
|
||||
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4846,7 +4797,8 @@ i915_gem_load(struct drm_device *dev)
|
|||
spin_unlock(&shrink_list_lock);
|
||||
|
||||
/* Old X drivers will take 0-2 for front, back, depth buffers */
|
||||
dev_priv->fence_reg_start = 3;
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
dev_priv->fence_reg_start = 3;
|
||||
|
||||
if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
dev_priv->num_fence_regs = 16;
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pnp.h>
|
||||
#include "linux/string.h"
|
||||
#include "linux/bitops.h"
|
||||
#include "drmP.h"
|
||||
|
@ -83,120 +81,6 @@
|
|||
* to match what the GPU expects.
|
||||
*/
|
||||
|
||||
#define MCHBAR_I915 0x44
|
||||
#define MCHBAR_I965 0x48
|
||||
#define MCHBAR_SIZE (4*4096)
|
||||
|
||||
#define DEVEN_REG 0x54
|
||||
#define DEVEN_MCHBAR_EN (1 << 28)
|
||||
|
||||
/* Allocate space for the MCH regs if needed, return nonzero on error */
|
||||
static int
|
||||
intel_alloc_mchbar_resource(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp_lo, temp_hi = 0;
|
||||
u64 mchbar_addr;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_I965G(dev))
|
||||
pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
|
||||
pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
|
||||
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
|
||||
|
||||
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
|
||||
#ifdef CONFIG_PNP
|
||||
if (mchbar_addr &&
|
||||
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get some space for it */
|
||||
ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
|
||||
MCHBAR_SIZE, MCHBAR_SIZE,
|
||||
PCIBIOS_MIN_MEM,
|
||||
0, pcibios_align_resource,
|
||||
dev_priv->bridge_dev);
|
||||
if (ret) {
|
||||
DRM_DEBUG_DRIVER("failed bus alloc: %d\n", ret);
|
||||
dev_priv->mch_res.start = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_I965G(dev))
|
||||
pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
|
||||
upper_32_bits(dev_priv->mch_res.start));
|
||||
|
||||
pci_write_config_dword(dev_priv->bridge_dev, reg,
|
||||
lower_32_bits(dev_priv->mch_res.start));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Setup MCHBAR if possible, return true if we should disable it again */
|
||||
static bool
|
||||
intel_setup_mchbar(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp;
|
||||
bool need_disable = false, enabled;
|
||||
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
|
||||
enabled = !!(temp & DEVEN_MCHBAR_EN);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
enabled = temp & 1;
|
||||
}
|
||||
|
||||
/* If it's already enabled, don't have to do anything */
|
||||
if (enabled)
|
||||
goto out;
|
||||
|
||||
if (intel_alloc_mchbar_resource(dev))
|
||||
goto out;
|
||||
|
||||
need_disable = true;
|
||||
|
||||
/* Space is allocated or reserved, so enable it. */
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
|
||||
temp | DEVEN_MCHBAR_EN);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
|
||||
}
|
||||
out:
|
||||
return need_disable;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_teardown_mchbar(struct drm_device *dev, bool disable)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
|
||||
u32 temp;
|
||||
|
||||
if (disable) {
|
||||
if (IS_I915G(dev) || IS_I915GM(dev)) {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
|
||||
temp &= ~DEVEN_MCHBAR_EN;
|
||||
pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
|
||||
} else {
|
||||
pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
|
||||
temp &= ~1;
|
||||
pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
|
||||
}
|
||||
}
|
||||
|
||||
if (dev_priv->mch_res.start)
|
||||
release_resource(&dev_priv->mch_res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects bit 6 swizzling of address lookup between IGD access and CPU
|
||||
* access through main memory.
|
||||
|
@ -207,7 +91,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
bool need_disable;
|
||||
|
||||
if (IS_IRONLAKE(dev)) {
|
||||
/* On Ironlake whatever DRAM config, GPU always do
|
||||
|
@ -224,9 +107,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|||
} else if (IS_MOBILE(dev)) {
|
||||
uint32_t dcc;
|
||||
|
||||
/* Try to make sure MCHBAR is enabled before poking at it */
|
||||
need_disable = intel_setup_mchbar(dev);
|
||||
|
||||
/* On mobile 9xx chipsets, channel interleave by the CPU is
|
||||
* determined by DCC. For single-channel, neither the CPU
|
||||
* nor the GPU do swizzling. For dual channel interleaved,
|
||||
|
@ -266,8 +146,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|||
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
}
|
||||
|
||||
intel_teardown_mchbar(dev, need_disable);
|
||||
} else {
|
||||
/* The 965, G33, and newer, have a very flexible memory
|
||||
* configuration. It will enable dual-channel mode
|
||||
|
@ -302,39 +180,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|||
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether an object is currently fenceable. If not, it may need
|
||||
* to be unbound and have its pitch adjusted.
|
||||
*/
|
||||
bool
|
||||
i915_obj_fenceable(struct drm_device *dev, struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
if (IS_I965G(dev)) {
|
||||
/* The 965 can have fences at any page boundary. */
|
||||
if (obj->size & 4095)
|
||||
return false;
|
||||
return true;
|
||||
} else if (IS_I9XX(dev)) {
|
||||
if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
|
||||
return false;
|
||||
} else {
|
||||
if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Power of two sized... */
|
||||
if (obj->size & (obj->size - 1))
|
||||
return false;
|
||||
|
||||
/* Objects must be size aligned as well */
|
||||
if (obj_priv->gtt_offset & (obj->size - 1))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Check pitch constriants for all chips & tiling formats */
|
||||
bool
|
||||
i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
|
||||
|
@ -391,7 +236,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
bool
|
||||
i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
@ -491,12 +336,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* If we've changed tiling, GTT-mappings of the object
|
||||
* need to re-fault to ensure that the correct fence register
|
||||
* setup is in place.
|
||||
*/
|
||||
i915_gem_release_mmap(obj);
|
||||
|
||||
obj_priv->tiling_mode = args->tiling_mode;
|
||||
obj_priv->stride = args->stride;
|
||||
}
|
||||
|
|
|
@ -269,6 +269,57 @@ static void i915_hotplug_work_func(struct work_struct *work)
|
|||
drm_sysfs_hotplug_event(dev);
|
||||
}
|
||||
|
||||
static void i915_handle_rps_change(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
u32 busy_up, busy_down, max_avg, min_avg;
|
||||
u16 rgvswctl;
|
||||
u8 new_delay = dev_priv->cur_delay;
|
||||
|
||||
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
|
||||
busy_up = I915_READ(RCPREVBSYTUPAVG);
|
||||
busy_down = I915_READ(RCPREVBSYTDNAVG);
|
||||
max_avg = I915_READ(RCBMAXAVG);
|
||||
min_avg = I915_READ(RCBMINAVG);
|
||||
|
||||
/* Handle RCS change request from hw */
|
||||
if (busy_up > max_avg) {
|
||||
if (dev_priv->cur_delay != dev_priv->max_delay)
|
||||
new_delay = dev_priv->cur_delay - 1;
|
||||
if (new_delay < dev_priv->max_delay)
|
||||
new_delay = dev_priv->max_delay;
|
||||
} else if (busy_down < min_avg) {
|
||||
if (dev_priv->cur_delay != dev_priv->min_delay)
|
||||
new_delay = dev_priv->cur_delay + 1;
|
||||
if (new_delay > dev_priv->min_delay)
|
||||
new_delay = dev_priv->min_delay;
|
||||
}
|
||||
|
||||
DRM_DEBUG("rps change requested: %d -> %d\n",
|
||||
dev_priv->cur_delay, new_delay);
|
||||
|
||||
rgvswctl = I915_READ(MEMSWCTL);
|
||||
if (rgvswctl & MEMCTL_CMD_STS) {
|
||||
DRM_ERROR("gpu busy, RCS change rejected\n");
|
||||
return; /* still busy with another command */
|
||||
}
|
||||
|
||||
/* Program the new state */
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
POSTING_READ(MEMSWCTL);
|
||||
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
|
||||
dev_priv->cur_delay = new_delay;
|
||||
|
||||
DRM_DEBUG("rps changed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
irqreturn_t ironlake_irq_handler(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
|
@ -331,6 +382,11 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
|
|||
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
|
||||
}
|
||||
|
||||
if (de_iir & DE_PCU_EVENT) {
|
||||
I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
|
||||
i915_handle_rps_change(dev);
|
||||
}
|
||||
|
||||
/* should clear PCH hotplug event before clear CPU irq */
|
||||
I915_WRITE(SDEIIR, pch_iir);
|
||||
I915_WRITE(GTIIR, gt_iir);
|
||||
|
@ -376,6 +432,121 @@ static void i915_error_work_func(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
static struct drm_i915_error_object *
|
||||
i915_error_object_create(struct drm_device *dev,
|
||||
struct drm_gem_object *src)
|
||||
{
|
||||
struct drm_i915_error_object *dst;
|
||||
struct drm_i915_gem_object *src_priv;
|
||||
int page, page_count;
|
||||
|
||||
if (src == NULL)
|
||||
return NULL;
|
||||
|
||||
src_priv = src->driver_private;
|
||||
if (src_priv->pages == NULL)
|
||||
return NULL;
|
||||
|
||||
page_count = src->size / PAGE_SIZE;
|
||||
|
||||
dst = kmalloc(sizeof(*dst) + page_count * sizeof (u32 *), GFP_ATOMIC);
|
||||
if (dst == NULL)
|
||||
return NULL;
|
||||
|
||||
for (page = 0; page < page_count; page++) {
|
||||
void *s, *d = kmalloc(PAGE_SIZE, GFP_ATOMIC);
|
||||
if (d == NULL)
|
||||
goto unwind;
|
||||
s = kmap_atomic(src_priv->pages[page], KM_USER0);
|
||||
memcpy(d, s, PAGE_SIZE);
|
||||
kunmap_atomic(s, KM_USER0);
|
||||
dst->pages[page] = d;
|
||||
}
|
||||
dst->page_count = page_count;
|
||||
dst->gtt_offset = src_priv->gtt_offset;
|
||||
|
||||
return dst;
|
||||
|
||||
unwind:
|
||||
while (page--)
|
||||
kfree(dst->pages[page]);
|
||||
kfree(dst);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
i915_error_object_free(struct drm_i915_error_object *obj)
|
||||
{
|
||||
int page;
|
||||
|
||||
if (obj == NULL)
|
||||
return;
|
||||
|
||||
for (page = 0; page < obj->page_count; page++)
|
||||
kfree(obj->pages[page]);
|
||||
|
||||
kfree(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
i915_error_state_free(struct drm_device *dev,
|
||||
struct drm_i915_error_state *error)
|
||||
{
|
||||
i915_error_object_free(error->batchbuffer[0]);
|
||||
i915_error_object_free(error->batchbuffer[1]);
|
||||
i915_error_object_free(error->ringbuffer);
|
||||
kfree(error->active_bo);
|
||||
kfree(error);
|
||||
}
|
||||
|
||||
static u32
|
||||
i915_get_bbaddr(struct drm_device *dev, u32 *ring)
|
||||
{
|
||||
u32 cmd;
|
||||
|
||||
if (IS_I830(dev) || IS_845G(dev))
|
||||
cmd = MI_BATCH_BUFFER;
|
||||
else if (IS_I965G(dev))
|
||||
cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
|
||||
MI_BATCH_NON_SECURE_I965);
|
||||
else
|
||||
cmd = (MI_BATCH_BUFFER_START | (2 << 6));
|
||||
|
||||
return ring[0] == cmd ? ring[1] : 0;
|
||||
}
|
||||
|
||||
static u32
|
||||
i915_ringbuffer_last_batch(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 head, bbaddr;
|
||||
u32 *ring;
|
||||
|
||||
/* Locate the current position in the ringbuffer and walk back
|
||||
* to find the most recently dispatched batch buffer.
|
||||
*/
|
||||
bbaddr = 0;
|
||||
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||
ring = (u32 *)(dev_priv->ring.virtual_start + head);
|
||||
|
||||
while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
|
||||
bbaddr = i915_get_bbaddr(dev, ring);
|
||||
if (bbaddr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bbaddr == 0) {
|
||||
ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size);
|
||||
while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
|
||||
bbaddr = i915_get_bbaddr(dev, ring);
|
||||
if (bbaddr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bbaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_capture_error_state - capture an error record for later analysis
|
||||
* @dev: drm device
|
||||
|
@ -388,19 +559,26 @@ static void i915_error_work_func(struct work_struct *work)
|
|||
static void i915_capture_error_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
struct drm_i915_error_state *error;
|
||||
struct drm_gem_object *batchbuffer[2];
|
||||
unsigned long flags;
|
||||
u32 bbaddr;
|
||||
int count;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
if (dev_priv->first_error)
|
||||
goto out;
|
||||
error = dev_priv->first_error;
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
error = kmalloc(sizeof(*error), GFP_ATOMIC);
|
||||
if (!error) {
|
||||
DRM_DEBUG_DRIVER("out ot memory, not capturing error state\n");
|
||||
goto out;
|
||||
DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
|
||||
return;
|
||||
}
|
||||
|
||||
error->seqno = i915_get_gem_seqno(dev);
|
||||
error->eir = I915_READ(EIR);
|
||||
error->pgtbl_er = I915_READ(PGTBL_ER);
|
||||
error->pipeastat = I915_READ(PIPEASTAT);
|
||||
|
@ -411,6 +589,7 @@ static void i915_capture_error_state(struct drm_device *dev)
|
|||
error->ipehr = I915_READ(IPEHR);
|
||||
error->instdone = I915_READ(INSTDONE);
|
||||
error->acthd = I915_READ(ACTHD);
|
||||
error->bbaddr = 0;
|
||||
} else {
|
||||
error->ipeir = I915_READ(IPEIR_I965);
|
||||
error->ipehr = I915_READ(IPEHR_I965);
|
||||
|
@ -418,14 +597,101 @@ static void i915_capture_error_state(struct drm_device *dev)
|
|||
error->instps = I915_READ(INSTPS);
|
||||
error->instdone1 = I915_READ(INSTDONE1);
|
||||
error->acthd = I915_READ(ACTHD_I965);
|
||||
error->bbaddr = I915_READ64(BB_ADDR);
|
||||
}
|
||||
|
||||
bbaddr = i915_ringbuffer_last_batch(dev);
|
||||
|
||||
/* Grab the current batchbuffer, most likely to have crashed. */
|
||||
batchbuffer[0] = NULL;
|
||||
batchbuffer[1] = NULL;
|
||||
count = 0;
|
||||
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
|
||||
struct drm_gem_object *obj = obj_priv->obj;
|
||||
|
||||
if (batchbuffer[0] == NULL &&
|
||||
bbaddr >= obj_priv->gtt_offset &&
|
||||
bbaddr < obj_priv->gtt_offset + obj->size)
|
||||
batchbuffer[0] = obj;
|
||||
|
||||
if (batchbuffer[1] == NULL &&
|
||||
error->acthd >= obj_priv->gtt_offset &&
|
||||
error->acthd < obj_priv->gtt_offset + obj->size &&
|
||||
batchbuffer[0] != obj)
|
||||
batchbuffer[1] = obj;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
/* We need to copy these to an anonymous buffer as the simplest
|
||||
* method to avoid being overwritten by userpace.
|
||||
*/
|
||||
error->batchbuffer[0] = i915_error_object_create(dev, batchbuffer[0]);
|
||||
error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
|
||||
|
||||
/* Record the ringbuffer */
|
||||
error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj);
|
||||
|
||||
/* Record buffers on the active list. */
|
||||
error->active_bo = NULL;
|
||||
error->active_bo_count = 0;
|
||||
|
||||
if (count)
|
||||
error->active_bo = kmalloc(sizeof(*error->active_bo)*count,
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (error->active_bo) {
|
||||
int i = 0;
|
||||
list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
|
||||
struct drm_gem_object *obj = obj_priv->obj;
|
||||
|
||||
error->active_bo[i].size = obj->size;
|
||||
error->active_bo[i].name = obj->name;
|
||||
error->active_bo[i].seqno = obj_priv->last_rendering_seqno;
|
||||
error->active_bo[i].gtt_offset = obj_priv->gtt_offset;
|
||||
error->active_bo[i].read_domains = obj->read_domains;
|
||||
error->active_bo[i].write_domain = obj->write_domain;
|
||||
error->active_bo[i].fence_reg = obj_priv->fence_reg;
|
||||
error->active_bo[i].pinned = 0;
|
||||
if (obj_priv->pin_count > 0)
|
||||
error->active_bo[i].pinned = 1;
|
||||
if (obj_priv->user_pin_count > 0)
|
||||
error->active_bo[i].pinned = -1;
|
||||
error->active_bo[i].tiling = obj_priv->tiling_mode;
|
||||
error->active_bo[i].dirty = obj_priv->dirty;
|
||||
error->active_bo[i].purgeable = obj_priv->madv != I915_MADV_WILLNEED;
|
||||
|
||||
if (++i == count)
|
||||
break;
|
||||
}
|
||||
error->active_bo_count = i;
|
||||
}
|
||||
|
||||
do_gettimeofday(&error->time);
|
||||
|
||||
dev_priv->first_error = error;
|
||||
|
||||
out:
|
||||
spin_lock_irqsave(&dev_priv->error_lock, flags);
|
||||
if (dev_priv->first_error == NULL) {
|
||||
dev_priv->first_error = error;
|
||||
error = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
|
||||
if (error)
|
||||
i915_error_state_free(dev, error);
|
||||
}
|
||||
|
||||
void i915_destroy_error_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_error_state *error;
|
||||
|
||||
spin_lock(&dev_priv->error_lock);
|
||||
error = dev_priv->first_error;
|
||||
dev_priv->first_error = NULL;
|
||||
spin_unlock(&dev_priv->error_lock);
|
||||
|
||||
if (error)
|
||||
i915_error_state_free(dev, error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1064,6 +1330,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
|
|||
I915_WRITE(SDEIER, dev_priv->pch_irq_enable_reg);
|
||||
(void) I915_READ(SDEIER);
|
||||
|
||||
if (IS_IRONLAKE_M(dev)) {
|
||||
/* Clear & enable PCU event interrupts */
|
||||
I915_WRITE(DEIIR, DE_PCU_EVENT);
|
||||
I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
|
||||
ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#define GC_CLOCK_100_200 (1 << 0)
|
||||
#define GC_CLOCK_100_133 (2 << 0)
|
||||
#define GC_CLOCK_166_250 (3 << 0)
|
||||
#define GCFGC2 0xda
|
||||
#define GCFGC 0xf0 /* 915+ only */
|
||||
#define GC_LOW_FREQUENCY_ENABLE (1 << 7)
|
||||
#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
|
||||
|
@ -282,7 +283,7 @@
|
|||
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
|
||||
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
|
||||
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
|
||||
#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14)
|
||||
#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
|
||||
#define I915_HWB_OOM_INTERRUPT (1<<13)
|
||||
#define I915_SYNC_STATUS_INTERRUPT (1<<12)
|
||||
#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
|
||||
|
@ -306,11 +307,14 @@
|
|||
#define I915_ERROR_MEMORY_REFRESH (1<<1)
|
||||
#define I915_ERROR_INSTRUCTION (1<<0)
|
||||
#define INSTPM 0x020c0
|
||||
#define INSTPM_SELF_EN (1<<12) /* 915GM only */
|
||||
#define ACTHD 0x020c8
|
||||
#define FW_BLC 0x020d8
|
||||
#define FW_BLC2 0x020dc
|
||||
#define FW_BLC_SELF 0x020e0 /* 915+ only */
|
||||
#define FW_BLC_SELF_EN (1<<15)
|
||||
#define FW_BLC_SELF_EN_MASK (1<<31)
|
||||
#define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */
|
||||
#define FW_BLC_SELF_EN (1<<15) /* 945 only */
|
||||
#define MM_BURST_LENGTH 0x00700000
|
||||
#define MM_FIFO_WATERMARK 0x0001F000
|
||||
#define LM_BURST_LENGTH 0x00000700
|
||||
|
@ -324,6 +328,7 @@
|
|||
#define CM0_COLOR_EVICT_DISABLE (1<<3)
|
||||
#define CM0_DEPTH_WRITE_DISABLE (1<<1)
|
||||
#define CM0_RC_OP_FLUSH_DISABLE (1<<0)
|
||||
#define BB_ADDR 0x02140 /* 8 bytes */
|
||||
#define GFX_FLSH_CNTL 0x02170 /* 915+ only */
|
||||
|
||||
|
||||
|
@ -784,10 +789,144 @@
|
|||
#define CLKCFG_MEM_800 (3 << 4)
|
||||
#define CLKCFG_MEM_MASK (7 << 4)
|
||||
|
||||
/** GM965 GM45 render standby register */
|
||||
#define MCHBAR_RENDER_STANDBY 0x111B8
|
||||
#define CRSTANDVID 0x11100
|
||||
#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
|
||||
#define PXVFREQ_PX_MASK 0x7f000000
|
||||
#define PXVFREQ_PX_SHIFT 24
|
||||
#define VIDFREQ_BASE 0x11110
|
||||
#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */
|
||||
#define VIDFREQ2 0x11114
|
||||
#define VIDFREQ3 0x11118
|
||||
#define VIDFREQ4 0x1111c
|
||||
#define VIDFREQ_P0_MASK 0x1f000000
|
||||
#define VIDFREQ_P0_SHIFT 24
|
||||
#define VIDFREQ_P0_CSCLK_MASK 0x00f00000
|
||||
#define VIDFREQ_P0_CSCLK_SHIFT 20
|
||||
#define VIDFREQ_P0_CRCLK_MASK 0x000f0000
|
||||
#define VIDFREQ_P0_CRCLK_SHIFT 16
|
||||
#define VIDFREQ_P1_MASK 0x00001f00
|
||||
#define VIDFREQ_P1_SHIFT 8
|
||||
#define VIDFREQ_P1_CSCLK_MASK 0x000000f0
|
||||
#define VIDFREQ_P1_CSCLK_SHIFT 4
|
||||
#define VIDFREQ_P1_CRCLK_MASK 0x0000000f
|
||||
#define INTTOEXT_BASE_ILK 0x11300
|
||||
#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */
|
||||
#define INTTOEXT_MAP3_SHIFT 24
|
||||
#define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT)
|
||||
#define INTTOEXT_MAP2_SHIFT 16
|
||||
#define INTTOEXT_MAP2_MASK (0x1f << INTTOEXT_MAP2_SHIFT)
|
||||
#define INTTOEXT_MAP1_SHIFT 8
|
||||
#define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT)
|
||||
#define INTTOEXT_MAP0_SHIFT 0
|
||||
#define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT)
|
||||
#define MEMSWCTL 0x11170 /* Ironlake only */
|
||||
#define MEMCTL_CMD_MASK 0xe000
|
||||
#define MEMCTL_CMD_SHIFT 13
|
||||
#define MEMCTL_CMD_RCLK_OFF 0
|
||||
#define MEMCTL_CMD_RCLK_ON 1
|
||||
#define MEMCTL_CMD_CHFREQ 2
|
||||
#define MEMCTL_CMD_CHVID 3
|
||||
#define MEMCTL_CMD_VMMOFF 4
|
||||
#define MEMCTL_CMD_VMMON 5
|
||||
#define MEMCTL_CMD_STS (1<<12) /* write 1 triggers command, clears
|
||||
when command complete */
|
||||
#define MEMCTL_FREQ_MASK 0x0f00 /* jitter, from 0-15 */
|
||||
#define MEMCTL_FREQ_SHIFT 8
|
||||
#define MEMCTL_SFCAVM (1<<7)
|
||||
#define MEMCTL_TGT_VID_MASK 0x007f
|
||||
#define MEMIHYST 0x1117c
|
||||
#define MEMINTREN 0x11180 /* 16 bits */
|
||||
#define MEMINT_RSEXIT_EN (1<<8)
|
||||
#define MEMINT_CX_SUPR_EN (1<<7)
|
||||
#define MEMINT_CONT_BUSY_EN (1<<6)
|
||||
#define MEMINT_AVG_BUSY_EN (1<<5)
|
||||
#define MEMINT_EVAL_CHG_EN (1<<4)
|
||||
#define MEMINT_MON_IDLE_EN (1<<3)
|
||||
#define MEMINT_UP_EVAL_EN (1<<2)
|
||||
#define MEMINT_DOWN_EVAL_EN (1<<1)
|
||||
#define MEMINT_SW_CMD_EN (1<<0)
|
||||
#define MEMINTRSTR 0x11182 /* 16 bits */
|
||||
#define MEM_RSEXIT_MASK 0xc000
|
||||
#define MEM_RSEXIT_SHIFT 14
|
||||
#define MEM_CONT_BUSY_MASK 0x3000
|
||||
#define MEM_CONT_BUSY_SHIFT 12
|
||||
#define MEM_AVG_BUSY_MASK 0x0c00
|
||||
#define MEM_AVG_BUSY_SHIFT 10
|
||||
#define MEM_EVAL_CHG_MASK 0x0300
|
||||
#define MEM_EVAL_BUSY_SHIFT 8
|
||||
#define MEM_MON_IDLE_MASK 0x00c0
|
||||
#define MEM_MON_IDLE_SHIFT 6
|
||||
#define MEM_UP_EVAL_MASK 0x0030
|
||||
#define MEM_UP_EVAL_SHIFT 4
|
||||
#define MEM_DOWN_EVAL_MASK 0x000c
|
||||
#define MEM_DOWN_EVAL_SHIFT 2
|
||||
#define MEM_SW_CMD_MASK 0x0003
|
||||
#define MEM_INT_STEER_GFX 0
|
||||
#define MEM_INT_STEER_CMR 1
|
||||
#define MEM_INT_STEER_SMI 2
|
||||
#define MEM_INT_STEER_SCI 3
|
||||
#define MEMINTRSTS 0x11184
|
||||
#define MEMINT_RSEXIT (1<<7)
|
||||
#define MEMINT_CONT_BUSY (1<<6)
|
||||
#define MEMINT_AVG_BUSY (1<<5)
|
||||
#define MEMINT_EVAL_CHG (1<<4)
|
||||
#define MEMINT_MON_IDLE (1<<3)
|
||||
#define MEMINT_UP_EVAL (1<<2)
|
||||
#define MEMINT_DOWN_EVAL (1<<1)
|
||||
#define MEMINT_SW_CMD (1<<0)
|
||||
#define MEMMODECTL 0x11190
|
||||
#define MEMMODE_BOOST_EN (1<<31)
|
||||
#define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */
|
||||
#define MEMMODE_BOOST_FREQ_SHIFT 24
|
||||
#define MEMMODE_IDLE_MODE_MASK 0x00030000
|
||||
#define MEMMODE_IDLE_MODE_SHIFT 16
|
||||
#define MEMMODE_IDLE_MODE_EVAL 0
|
||||
#define MEMMODE_IDLE_MODE_CONT 1
|
||||
#define MEMMODE_HWIDLE_EN (1<<15)
|
||||
#define MEMMODE_SWMODE_EN (1<<14)
|
||||
#define MEMMODE_RCLK_GATE (1<<13)
|
||||
#define MEMMODE_HW_UPDATE (1<<12)
|
||||
#define MEMMODE_FSTART_MASK 0x00000f00 /* starting jitter, 0-15 */
|
||||
#define MEMMODE_FSTART_SHIFT 8
|
||||
#define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */
|
||||
#define MEMMODE_FMAX_SHIFT 4
|
||||
#define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */
|
||||
#define RCBMAXAVG 0x1119c
|
||||
#define MEMSWCTL2 0x1119e /* Cantiga only */
|
||||
#define SWMEMCMD_RENDER_OFF (0 << 13)
|
||||
#define SWMEMCMD_RENDER_ON (1 << 13)
|
||||
#define SWMEMCMD_SWFREQ (2 << 13)
|
||||
#define SWMEMCMD_TARVID (3 << 13)
|
||||
#define SWMEMCMD_VRM_OFF (4 << 13)
|
||||
#define SWMEMCMD_VRM_ON (5 << 13)
|
||||
#define CMDSTS (1<<12)
|
||||
#define SFCAVM (1<<11)
|
||||
#define SWFREQ_MASK 0x0380 /* P0-7 */
|
||||
#define SWFREQ_SHIFT 7
|
||||
#define TARVID_MASK 0x001f
|
||||
#define MEMSTAT_CTG 0x111a0
|
||||
#define RCBMINAVG 0x111a0
|
||||
#define RCUPEI 0x111b0
|
||||
#define RCDNEI 0x111b4
|
||||
#define MCHBAR_RENDER_STANDBY 0x111b8
|
||||
#define RCX_SW_EXIT (1<<23)
|
||||
#define RSX_STATUS_MASK 0x00700000
|
||||
#define VIDCTL 0x111c0
|
||||
#define VIDSTS 0x111c8
|
||||
#define VIDSTART 0x111cc /* 8 bits */
|
||||
#define MEMSTAT_ILK 0x111f8
|
||||
#define MEMSTAT_VID_MASK 0x7f00
|
||||
#define MEMSTAT_VID_SHIFT 8
|
||||
#define MEMSTAT_PSTATE_MASK 0x00f8
|
||||
#define MEMSTAT_PSTATE_SHIFT 3
|
||||
#define MEMSTAT_MON_ACTV (1<<2)
|
||||
#define MEMSTAT_SRC_CTL_MASK 0x0003
|
||||
#define MEMSTAT_SRC_CTL_CORE 0
|
||||
#define MEMSTAT_SRC_CTL_TRB 1
|
||||
#define MEMSTAT_SRC_CTL_THM 2
|
||||
#define MEMSTAT_SRC_CTL_STDBY 3
|
||||
#define RCPREVBSYTUPAVG 0x113b8
|
||||
#define RCPREVBSYTDNAVG 0x113bc
|
||||
#define PEG_BAND_GAP_DATA 0x14d68
|
||||
|
||||
/*
|
||||
|
|
|
@ -682,6 +682,8 @@ void i915_restore_display(struct drm_device *dev)
|
|||
I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->savePP_OFF_DELAYS);
|
||||
I915_WRITE(PCH_PP_DIVISOR, dev_priv->savePP_DIVISOR);
|
||||
I915_WRITE(PCH_PP_CONTROL, dev_priv->savePP_CONTROL);
|
||||
I915_WRITE(MCHBAR_RENDER_STANDBY,
|
||||
dev_priv->saveMCHBAR_RENDER_STANDBY);
|
||||
} else {
|
||||
I915_WRITE(PFIT_PGM_RATIOS, dev_priv->savePFIT_PGM_RATIOS);
|
||||
I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
|
||||
|
@ -745,11 +747,16 @@ int i915_save_state(struct drm_device *dev)
|
|||
dev_priv->saveGTIMR = I915_READ(GTIMR);
|
||||
dev_priv->saveFDI_RXA_IMR = I915_READ(FDI_RXA_IMR);
|
||||
dev_priv->saveFDI_RXB_IMR = I915_READ(FDI_RXB_IMR);
|
||||
dev_priv->saveMCHBAR_RENDER_STANDBY =
|
||||
I915_READ(MCHBAR_RENDER_STANDBY);
|
||||
} else {
|
||||
dev_priv->saveIER = I915_READ(IER);
|
||||
dev_priv->saveIMR = I915_READ(IMR);
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||
|
||||
|
@ -820,6 +827,9 @@ int i915_restore_state(struct drm_device *dev)
|
|||
/* Clock gating state */
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_drps(dev);
|
||||
|
||||
/* Cache mode state */
|
||||
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||
|
||||
|
|
|
@ -1188,25 +1188,30 @@ static void intel_update_fbc(struct drm_crtc *crtc,
|
|||
if (intel_fb->obj->size > dev_priv->cfb_size) {
|
||||
DRM_DEBUG_KMS("framebuffer too large, disabling "
|
||||
"compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
|
||||
goto out_disable;
|
||||
}
|
||||
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
|
||||
(mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
|
||||
DRM_DEBUG_KMS("mode incompatible with compression, "
|
||||
"disabling\n");
|
||||
dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
|
||||
goto out_disable;
|
||||
}
|
||||
if ((mode->hdisplay > 2048) ||
|
||||
(mode->vdisplay > 1536)) {
|
||||
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
|
||||
dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
|
||||
goto out_disable;
|
||||
}
|
||||
if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
|
||||
DRM_DEBUG_KMS("plane not 0, disabling compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
|
||||
goto out_disable;
|
||||
}
|
||||
if (obj_priv->tiling_mode != I915_TILING_X) {
|
||||
DRM_DEBUG_KMS("framebuffer not tiled, disabling compression\n");
|
||||
dev_priv->no_fbc_reason = FBC_NOT_TILED;
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
|
@ -2757,11 +2762,22 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
|
|||
srwm = total_size - sr_entries;
|
||||
if (srwm < 0)
|
||||
srwm = 1;
|
||||
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
|
||||
|
||||
if (IS_I945G(dev) || IS_I945GM(dev))
|
||||
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
|
||||
else if (IS_I915GM(dev)) {
|
||||
/* 915M has a smaller SRWM field */
|
||||
I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
|
||||
I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
|
||||
}
|
||||
} else {
|
||||
/* Turn off self refresh if both pipes are enabled */
|
||||
I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
|
||||
& ~FW_BLC_SELF_EN);
|
||||
if (IS_I945G(dev) || IS_I945GM(dev)) {
|
||||
I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
|
||||
& ~FW_BLC_SELF_EN);
|
||||
} else if (IS_I915GM(dev)) {
|
||||
I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
|
||||
}
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
|
||||
|
@ -4010,6 +4026,11 @@ static void intel_idle_update(struct work_struct *work)
|
|||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (IS_I945G(dev) || IS_I945GM(dev)) {
|
||||
DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
|
||||
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
/* Skip inactive CRTCs */
|
||||
if (!crtc->fb)
|
||||
|
@ -4043,9 +4064,17 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
|
|||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
if (!dev_priv->busy)
|
||||
if (!dev_priv->busy) {
|
||||
if (IS_I945G(dev) || IS_I945GM(dev)) {
|
||||
u32 fw_blc_self;
|
||||
|
||||
DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
|
||||
fw_blc_self = I915_READ(FW_BLC_SELF);
|
||||
fw_blc_self &= ~FW_BLC_SELF_EN;
|
||||
I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
|
||||
}
|
||||
dev_priv->busy = true;
|
||||
else
|
||||
} else
|
||||
mod_timer(&dev_priv->idle_timer, jiffies +
|
||||
msecs_to_jiffies(GPU_IDLE_TIMEOUT));
|
||||
|
||||
|
@ -4057,6 +4086,14 @@ void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
|
|||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
if (intel_fb->obj == obj) {
|
||||
if (!intel_crtc->busy) {
|
||||
if (IS_I945G(dev) || IS_I945GM(dev)) {
|
||||
u32 fw_blc_self;
|
||||
|
||||
DRM_DEBUG_DRIVER("disable memory self refresh on 945\n");
|
||||
fw_blc_self = I915_READ(FW_BLC_SELF);
|
||||
fw_blc_self &= ~FW_BLC_SELF_EN;
|
||||
I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
|
||||
}
|
||||
/* Non-busy -> busy, upclock */
|
||||
intel_increase_pllclock(crtc, true);
|
||||
intel_crtc->busy = true;
|
||||
|
@ -4586,6 +4623,91 @@ err_unref:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void ironlake_enable_drps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
|
||||
u8 fmax, fmin, fstart, vstart;
|
||||
int i = 0;
|
||||
|
||||
/* 100ms RC evaluation intervals */
|
||||
I915_WRITE(RCUPEI, 100000);
|
||||
I915_WRITE(RCDNEI, 100000);
|
||||
|
||||
/* Set max/min thresholds to 90ms and 80ms respectively */
|
||||
I915_WRITE(RCBMAXAVG, 90000);
|
||||
I915_WRITE(RCBMINAVG, 80000);
|
||||
|
||||
I915_WRITE(MEMIHYST, 1);
|
||||
|
||||
/* Set up min, max, and cur for interrupt handling */
|
||||
fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
|
||||
fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
|
||||
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
|
||||
MEMMODE_FSTART_SHIFT;
|
||||
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
|
||||
PXVFREQ_PX_SHIFT;
|
||||
|
||||
dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
|
||||
dev_priv->min_delay = fmin;
|
||||
dev_priv->cur_delay = fstart;
|
||||
|
||||
I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
|
||||
|
||||
/*
|
||||
* Interrupts will be enabled in ironlake_irq_postinstall
|
||||
*/
|
||||
|
||||
I915_WRITE(VIDSTART, vstart);
|
||||
POSTING_READ(VIDSTART);
|
||||
|
||||
rgvmodectl |= MEMMODE_SWMODE_EN;
|
||||
I915_WRITE(MEMMODECTL, rgvmodectl);
|
||||
|
||||
while (I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) {
|
||||
if (i++ > 100) {
|
||||
DRM_ERROR("stuck trying to change perf mode\n");
|
||||
break;
|
||||
}
|
||||
msleep(1);
|
||||
}
|
||||
msleep(1);
|
||||
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
POSTING_READ(MEMSWCTL);
|
||||
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
}
|
||||
|
||||
void ironlake_disable_drps(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 rgvswctl;
|
||||
u8 fstart;
|
||||
|
||||
/* Ack interrupts, disable EFC interrupt */
|
||||
I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
|
||||
I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
|
||||
I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
|
||||
I915_WRITE(DEIIR, DE_PCU_EVENT);
|
||||
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
|
||||
|
||||
/* Go back to the starting frequency */
|
||||
fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
|
||||
MEMMODE_FSTART_SHIFT;
|
||||
rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
|
||||
(fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
msleep(1);
|
||||
rgvswctl |= MEMCTL_CMD_STS;
|
||||
I915_WRITE(MEMSWCTL, rgvswctl);
|
||||
msleep(1);
|
||||
|
||||
}
|
||||
|
||||
void intel_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -4769,11 +4891,6 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
DRM_DEBUG_KMS("%d display pipe%s available.\n",
|
||||
num_pipe, num_pipe > 1 ? "s" : "");
|
||||
|
||||
if (IS_I85X(dev))
|
||||
pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
|
||||
else if (IS_I9XX(dev) || IS_G4X(dev))
|
||||
pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
|
||||
|
||||
for (i = 0; i < num_pipe; i++) {
|
||||
intel_crtc_init(dev, i);
|
||||
}
|
||||
|
@ -4782,6 +4899,9 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_enable_drps(dev);
|
||||
|
||||
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
|
||||
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
|
||||
(unsigned long)dev);
|
||||
|
@ -4829,6 +4949,9 @@ void intel_modeset_cleanup(struct drm_device *dev)
|
|||
drm_gem_object_unreference(dev_priv->pwrctx);
|
||||
}
|
||||
|
||||
if (IS_IRONLAKE_M(dev))
|
||||
ironlake_disable_drps(dev);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_mode_config_cleanup(dev);
|
||||
|
|
|
@ -209,6 +209,8 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
|
|||
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
|
||||
u16 *blue, int regno);
|
||||
extern void intel_init_clock_gating(struct drm_device *dev);
|
||||
extern void ironlake_enable_drps(struct drm_device *dev);
|
||||
extern void ironlake_disable_drps(struct drm_device *dev);
|
||||
|
||||
extern int intel_framebuffer_create(struct drm_device *dev,
|
||||
struct drm_mode_fb_cmd *mode_cmd,
|
||||
|
|
|
@ -655,8 +655,15 @@ static const struct dmi_system_id bad_lid_status[] = {
|
|||
*/
|
||||
static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
enum drm_connector_status status = connector_status_connected;
|
||||
|
||||
/* ACPI lid methods were generally unreliable in this generation, so
|
||||
* don't even bother.
|
||||
*/
|
||||
if (IS_I8XX(dev))
|
||||
return connector_status_connected;
|
||||
|
||||
if (!dmi_check_system(bad_lid_status) && !acpi_lid_open())
|
||||
status = connector_status_disconnected;
|
||||
|
||||
|
|
|
@ -199,16 +199,11 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over
|
|||
|
||||
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
|
||||
{
|
||||
struct drm_device *dev = overlay->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (OVERLAY_NONPHYSICAL(overlay->dev))
|
||||
io_mapping_unmap_atomic(overlay->virt_addr);
|
||||
|
||||
overlay->virt_addr = NULL;
|
||||
|
||||
I915_READ(OVADD); /* flush wc cashes */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -225,9 +220,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
|
|||
overlay->active = 1;
|
||||
overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(MI_FLUSH);
|
||||
OUT_RING(MI_NOOP);
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
|
||||
OUT_RING(overlay->flip_addr | OFC_UPDATE);
|
||||
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
|
@ -267,9 +260,7 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
|
|||
if (tmp & (1 << 17))
|
||||
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
|
||||
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_FLUSH);
|
||||
OUT_RING(MI_NOOP);
|
||||
BEGIN_LP_RING(2);
|
||||
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
|
||||
OUT_RING(flip_addr);
|
||||
ADVANCE_LP_RING();
|
||||
|
@ -338,9 +329,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
|||
/* wait for overlay to go idle */
|
||||
overlay->hw_wedged = SWITCH_OFF_STAGE_1;
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(MI_FLUSH);
|
||||
OUT_RING(MI_NOOP);
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
|
||||
OUT_RING(flip_addr);
|
||||
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
|
@ -358,9 +347,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
|
|||
/* turn overlay off */
|
||||
overlay->hw_wedged = SWITCH_OFF_STAGE_2;
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(MI_FLUSH);
|
||||
OUT_RING(MI_NOOP);
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||||
OUT_RING(flip_addr);
|
||||
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
|
@ -435,9 +422,7 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
|
|||
|
||||
overlay->hw_wedged = SWITCH_OFF_STAGE_2;
|
||||
|
||||
BEGIN_LP_RING(6);
|
||||
OUT_RING(MI_FLUSH);
|
||||
OUT_RING(MI_NOOP);
|
||||
BEGIN_LP_RING(4);
|
||||
OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
|
||||
OUT_RING(flip_addr);
|
||||
OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
|
||||
|
|
Loading…
Reference in a new issue