On Fri, Jul 12, 2013 at 06:08:22PM +0100, Chris Wilson wrote: > Currently, the register access code is split between i915_drv.c and > intel_pm.c. It only bares a superficial resemblance to the reset of the > powermanagement code, so move it all into its own file. This is to ease > further patches to enforce serialised register access. > > v2: Scan for random abuse of I915_WRITE_NOTRACE > v3: Take the opportunity to rename the GT functions as uncore. Uncore is > the term used by the hardware design (and bspec) for all functions > outside of the GPU (and CPU) cores in what is also known as the System > Agent. > > Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk> git am complains about a missing newline at EOF, but I guess Daniel will fix it on merge. Just bikesheds: As before, intel_uncore_(clear|check)_errors seems silly to me. Also if you extracted those as a separate patch to the gt funcs, you could have had just a simple file move + rename. And as you made me realize, I'm not horribly thrilled with the name uncore, I liked gt. For me, the distinction between _pm, and _uncore isn't really large enough, ie. many things in _pm are really uncore also (anything touching the punit/rps, etc). Also, since gt_funcs never really expanded, maybe just call it forcewake_funcs and be done with that (since uncore forcewake sounds weird to me). Final bikeshed, I would like to see the reset code in a separate file as well (included in this could be any GEM functions we have for reset only, and display as well). I'll bump my ack up to r-b now since I've looked at it a few times. Reviewed-by: Ben Widawsky <ben at bwidawsk.net> > --- > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/i915_debugfs.c | 12 +- > drivers/gpu/drm/i915/i915_dma.c | 8 +- > drivers/gpu/drm/i915/i915_drv.c | 268 +---------------- > drivers/gpu/drm/i915/i915_drv.h | 30 +- > drivers/gpu/drm/i915/i915_irq.c | 6 +- > drivers/gpu/drm/i915/intel_display.c | 3 +- > drivers/gpu/drm/i915/intel_drv.h | 1 - > drivers/gpu/drm/i915/intel_pm.c | 258 +--------------- > drivers/gpu/drm/i915/intel_uncore.c | 569 +++++++++++++++++++++++++++++++++++ > 10 files changed, 609 insertions(+), 547 deletions(-) > create mode 100644 drivers/gpu/drm/i915/intel_uncore.c > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > index 9d1da7c..b8449a8 100644 > --- a/drivers/gpu/drm/i915/Makefile > +++ b/drivers/gpu/drm/i915/Makefile > @@ -38,6 +38,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ > intel_sprite.o \ > intel_opregion.o \ > intel_sideband.o \ > + intel_uncore.o \ > dvo_ch7xxx.o \ > dvo_ch7017.o \ > dvo_ivch.o \ > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c > index 8637979..7231322 100644 > --- a/drivers/gpu/drm/i915/i915_debugfs.c > +++ b/drivers/gpu/drm/i915/i915_debugfs.c > @@ -987,9 +987,9 @@ static int gen6_drpc_info(struct seq_file *m) > if (ret) > return ret; > > - spin_lock_irq(&dev_priv->gt_lock); > - forcewake_count = dev_priv->forcewake_count; > - spin_unlock_irq(&dev_priv->gt_lock); > + spin_lock_irq(&dev_priv->uncore.lock); > + forcewake_count = dev_priv->uncore.forcewake_count; > + spin_unlock_irq(&dev_priv->uncore.lock); > > if (forcewake_count) { > seq_puts(m, "RC information inaccurate because somebody " > @@ -1373,9 +1373,9 @@ static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data) > struct drm_i915_private *dev_priv = dev->dev_private; > unsigned forcewake_count; > > - spin_lock_irq(&dev_priv->gt_lock); > - forcewake_count = dev_priv->forcewake_count; > - spin_unlock_irq(&dev_priv->gt_lock); > + spin_lock_irq(&dev_priv->uncore.lock); > + forcewake_count = dev_priv->uncore.forcewake_count; > + spin_unlock_irq(&dev_priv->uncore.lock); > > seq_printf(m, "forcewake count = %u\n", forcewake_count); > > diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c > index 6ce9033..a2ac6e6 100644 > --- a/drivers/gpu/drm/i915/i915_dma.c > +++ b/drivers/gpu/drm/i915/i915_dma.c > @@ -1445,10 +1445,7 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv) > */ > static void intel_early_sanitize_regs(struct drm_device *dev) > { > - struct drm_i915_private *dev_priv = dev->dev_private; > - > - if (HAS_FPGA_DBG_UNCLAIMED(dev)) > - I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > + intel_uncore_early_sanitize(dev); > } > > /** > @@ -1580,7 +1577,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) > intel_detect_pch(dev); > > intel_irq_init(dev); > - intel_gt_init(dev); > + intel_uncore_init(dev); > + intel_pm_init(dev); > > /* Try to make sure MCHBAR is enabled before poking at it */ > intel_setup_mchbar(dev); > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c > index b07362f..3c438a7 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -714,7 +714,7 @@ static int i915_drm_thaw(struct drm_device *dev) > { > int error = 0; > > - intel_gt_reset(dev); > + intel_uncore_reset(dev); > > if (drm_core_check_feature(dev, DRIVER_MODESET)) { > mutex_lock(&dev->struct_mutex); > @@ -740,7 +740,7 @@ int i915_resume(struct drm_device *dev) > > pci_set_master(dev->pdev); > > - intel_gt_reset(dev); > + intel_uncore_reset(dev); > > /* > * Platforms with opregion should have sane BIOS, older ones (gen3 and > @@ -761,140 +761,6 @@ int i915_resume(struct drm_device *dev) > return 0; > } > > -static int i8xx_do_reset(struct drm_device *dev) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - > - if (IS_I85X(dev)) > - return -ENODEV; > - > - I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); > - POSTING_READ(D_STATE); > - > - if (IS_I830(dev) || IS_845G(dev)) { > - I915_WRITE(DEBUG_RESET_I830, > - DEBUG_RESET_DISPLAY | > - DEBUG_RESET_RENDER | > - DEBUG_RESET_FULL); > - POSTING_READ(DEBUG_RESET_I830); > - msleep(1); > - > - I915_WRITE(DEBUG_RESET_I830, 0); > - POSTING_READ(DEBUG_RESET_I830); > - } > - > - msleep(1); > - > - I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); > - POSTING_READ(D_STATE); > - > - return 0; > -} > - > -static int i965_reset_complete(struct drm_device *dev) > -{ > - u8 gdrst; > - pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); > - return (gdrst & GRDOM_RESET_ENABLE) == 0; > -} > - > -static int i965_do_reset(struct drm_device *dev) > -{ > - int ret; > - > - /* > - * Set the domains we want to reset (GRDOM/bits 2 and 3) as > - * well as the reset bit (GR/bit 0). Setting the GR bit > - * triggers the reset; when done, the hardware will clear it. > - */ > - pci_write_config_byte(dev->pdev, I965_GDRST, > - GRDOM_RENDER | GRDOM_RESET_ENABLE); > - ret = wait_for(i965_reset_complete(dev), 500); > - if (ret) > - return ret; > - > - /* We can't reset render&media without also resetting display ... */ > - pci_write_config_byte(dev->pdev, I965_GDRST, > - GRDOM_MEDIA | GRDOM_RESET_ENABLE); > - > - ret = wait_for(i965_reset_complete(dev), 500); > - if (ret) > - return ret; > - > - pci_write_config_byte(dev->pdev, I965_GDRST, 0); > - > - return 0; > -} > - > -static int ironlake_do_reset(struct drm_device *dev) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - u32 gdrst; > - int ret; > - > - gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); > - gdrst &= ~GRDOM_MASK; > - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, > - gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); > - ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); > - if (ret) > - return ret; > - > - /* We can't reset render&media without also resetting display ... */ > - gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); > - gdrst &= ~GRDOM_MASK; > - I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, > - gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); > - return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); > -} > - > -static int gen6_do_reset(struct drm_device *dev) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - int ret; > - unsigned long irqflags; > - > - /* Hold gt_lock across reset to prevent any register access > - * with forcewake not set correctly > - */ > - spin_lock_irqsave(&dev_priv->gt_lock, irqflags); > - > - /* Reset the chip */ > - > - /* GEN6_GDRST is not in the gt power well, no need to check > - * for fifo space for the write or forcewake the chip for > - * the read > - */ > - I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); > - > - /* Spin waiting for the device to ack the reset request */ > - ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); > - > - /* If reset with a user forcewake, try to restore, otherwise turn it off */ > - if (dev_priv->forcewake_count) > - dev_priv->gt.force_wake_get(dev_priv); > - else > - dev_priv->gt.force_wake_put(dev_priv); > - > - /* Restore fifo count */ > - dev_priv->gt_fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > - > - spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); > - return ret; > -} > - > -int intel_gpu_reset(struct drm_device *dev) > -{ > - switch (INTEL_INFO(dev)->gen) { > - case 7: > - case 6: return gen6_do_reset(dev); > - case 5: return ironlake_do_reset(dev); > - case 4: return i965_do_reset(dev); > - case 2: return i8xx_do_reset(dev); > - default: return -ENODEV; > - } > -} > - > /** > * i915_reset - reset chip after a hang > * @dev: drm device to reset > @@ -1224,133 +1090,3 @@ module_exit(i915_exit); > MODULE_AUTHOR(DRIVER_AUTHOR); > MODULE_DESCRIPTION(DRIVER_DESC); > MODULE_LICENSE("GPL and additional rights"); > - > -/* We give fast paths for the really cool registers */ > -#define NEEDS_FORCE_WAKE(dev_priv, reg) \ > - ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ > - ((reg) < 0x40000) && \ > - ((reg) != FORCEWAKE)) > -static void > -ilk_dummy_write(struct drm_i915_private *dev_priv) > -{ > - /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up > - * the chip from rc6 before touching it for real. MI_MODE is masked, > - * hence harmless to write 0 into. */ > - I915_WRITE_NOTRACE(MI_MODE, 0); > -} > - > -static void > -hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) > -{ > - if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && > - (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > - DRM_ERROR("Unknown unclaimed register before writing to %x\n", > - reg); > - I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > - } > -} > - > -static void > -hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) > -{ > - if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && > - (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > - DRM_ERROR("Unclaimed write to %x\n", reg); > - I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > - } > -} > - > -#define __i915_read(x, y) \ > -u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ > - u##x val = 0; \ > - if (IS_GEN5(dev_priv->dev)) \ > - ilk_dummy_write(dev_priv); \ > - if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ > - unsigned long irqflags; \ > - spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \ > - if (dev_priv->forcewake_count == 0) \ > - dev_priv->gt.force_wake_get(dev_priv); \ > - val = read##y(dev_priv->regs + reg); \ > - if (dev_priv->forcewake_count == 0) \ > - dev_priv->gt.force_wake_put(dev_priv); \ > - spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \ > - } else { \ > - val = read##y(dev_priv->regs + reg); \ > - } \ > - trace_i915_reg_rw(false, reg, val, sizeof(val)); \ > - return val; \ > -} > - > -__i915_read(8, b) > -__i915_read(16, w) > -__i915_read(32, l) > -__i915_read(64, q) > -#undef __i915_read > - > -#define __i915_write(x, y) \ > -void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ > - u32 __fifo_ret = 0; \ > - trace_i915_reg_rw(true, reg, val, sizeof(val)); \ > - if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ > - __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ > - } \ > - if (IS_GEN5(dev_priv->dev)) \ > - ilk_dummy_write(dev_priv); \ > - hsw_unclaimed_reg_clear(dev_priv, reg); \ > - write##y(val, dev_priv->regs + reg); \ > - if (unlikely(__fifo_ret)) { \ > - gen6_gt_check_fifodbg(dev_priv); \ > - } \ > - hsw_unclaimed_reg_check(dev_priv, reg); \ > -} > -__i915_write(8, b) > -__i915_write(16, w) > -__i915_write(32, l) > -__i915_write(64, q) > -#undef __i915_write > - > -static const struct register_whitelist { > - uint64_t offset; > - uint32_t size; > - uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ > -} whitelist[] = { > - { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 }, > -}; > - > -int i915_reg_read_ioctl(struct drm_device *dev, > - void *data, struct drm_file *file) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - struct drm_i915_reg_read *reg = data; > - struct register_whitelist const *entry = whitelist; > - int i; > - > - for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) { > - if (entry->offset == reg->offset && > - (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask)) > - break; > - } > - > - if (i == ARRAY_SIZE(whitelist)) > - return -EINVAL; > - > - switch (entry->size) { > - case 8: > - reg->val = I915_READ64(reg->offset); > - break; > - case 4: > - reg->val = I915_READ(reg->offset); > - break; > - case 2: > - reg->val = I915_READ16(reg->offset); > - break; > - case 1: > - reg->val = I915_READ8(reg->offset); > - break; > - default: > - WARN_ON(1); > - return -EINVAL; > - } > - > - return 0; > -} > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index cef35d3..f14eddf 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -391,11 +391,20 @@ struct drm_i915_display_funcs { > /* pll clock increase/decrease */ > }; > > -struct drm_i915_gt_funcs { > +struct intel_uncore_funcs { > void (*force_wake_get)(struct drm_i915_private *dev_priv); > void (*force_wake_put)(struct drm_i915_private *dev_priv); > }; > > +struct intel_uncore { > + spinlock_t lock; /** lock is also taken in irq contexts. */ > + > + struct intel_uncore_funcs funcs; > + > + unsigned fifo_count; > + unsigned forcewake_count; > +}; > + > #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ > func(is_mobile) sep \ > func(is_i85x) sep \ > @@ -1024,14 +1033,7 @@ typedef struct drm_i915_private { > > void __iomem *regs; > > - struct drm_i915_gt_funcs gt; > - /** gt_fifo_count and the subsequent register write are synchronized > - * with dev->struct_mutex. */ > - unsigned gt_fifo_count; > - /** forcewake_count is protected by gt_lock */ > - unsigned forcewake_count; > - /** gt_lock is also taken in irq contexts. */ > - spinlock_t gt_lock; > + struct intel_uncore uncore; > > struct intel_gmbus gmbus[GMBUS_NUM_PORTS]; > > @@ -1624,8 +1626,13 @@ void i915_handle_error(struct drm_device *dev, bool wedged); > > extern void intel_irq_init(struct drm_device *dev); > extern void intel_hpd_init(struct drm_device *dev); > -extern void intel_gt_init(struct drm_device *dev); > -extern void intel_gt_reset(struct drm_device *dev); > +extern void intel_pm_init(struct drm_device *dev); > + > +extern void intel_uncore_early_sanitize(struct drm_device *dev); > +extern void intel_uncore_init(struct drm_device *dev); > +extern void intel_uncore_reset(struct drm_device *dev); > +extern void intel_uncore_clear_errors(struct drm_device *dev); > +extern void intel_uncore_check_errors(struct drm_device *dev); > > void > i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask); > @@ -2058,7 +2065,6 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, > */ > void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); > void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); > -int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); > > int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val); > int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val); > diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c > index 64db680f..59aec64 100644 > --- a/drivers/gpu/drm/i915/i915_irq.c > +++ b/drivers/gpu/drm/i915/i915_irq.c > @@ -1214,11 +1214,7 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg) > > /* We get interrupts on unclaimed registers, so check for this before we > * do any I915_{READ,WRITE}. */ > - if (IS_HASWELL(dev) && > - (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > - DRM_ERROR("Unclaimed register before interrupt\n"); > - I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > - } > + intel_uncore_check_errors(dev); > > /* disable master interrupt before clearing iir */ > de_ier = I915_READ(DEIER); > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index c79addd..4aca72f 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -10253,8 +10253,7 @@ intel_display_capture_error_state(struct drm_device *dev) > * well was on, so here we have to clear the FPGA_DBG_RM_NOCLAIM bit to > * prevent the next I915_WRITE from detecting it and printing an error > * message. */ > - if (HAS_POWER_WELL(dev)) > - I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > + intel_uncore_clear_errors(dev); > > return error; > } > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 5dfc1a0..f705ef3 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -804,7 +804,6 @@ extern void intel_init_power_well(struct drm_device *dev); > extern void intel_set_power_well(struct drm_device *dev, bool enable); > extern void intel_enable_gt_powersave(struct drm_device *dev); > extern void intel_disable_gt_powersave(struct drm_device *dev); > -extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); > extern void ironlake_teardown_rc6(struct drm_device *dev); > > extern bool intel_ddi_get_hw_state(struct intel_encoder *encoder, > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c > index fb4afaa..f6c3608 100644 > --- a/drivers/gpu/drm/i915/intel_pm.c > +++ b/drivers/gpu/drm/i915/intel_pm.c > @@ -32,8 +32,6 @@ > #include <linux/module.h> > #include <drm/i915_powerwell.h> > > -#define FORCEWAKE_ACK_TIMEOUT_MS 2 > - > /* FBC, or Frame Buffer Compression, is a technique employed to compress the > * framebuffer contents in-memory, aiming at reducing the required bandwidth > * during in-memory transfers and, therefore, reduce the power packet. > @@ -5284,254 +5282,6 @@ void intel_init_pm(struct drm_device *dev) > } > } > > -static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) > -{ > - u32 gt_thread_status_mask; > - > - if (IS_HASWELL(dev_priv->dev)) > - gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK_HSW; > - else > - gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK; > - > - /* w/a for a sporadic read returning 0 by waiting for the GT > - * thread to wake up. > - */ > - if (wait_for_atomic_us((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500)) > - DRM_ERROR("GT thread status wait timed out\n"); > -} > - > -static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE, 0); > - POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ > -} > - > -static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > -{ > - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0, > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > - > - I915_WRITE_NOTRACE(FORCEWAKE, 1); > - POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ > - > - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1), > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); > - > - /* WaRsForcewakeWaitTC0:snb */ > - __gen6_gt_wait_for_thread_c0(dev_priv); > -} > - > -static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); > - /* something from same cacheline, but !FORCEWAKE_MT */ > - POSTING_READ(ECOBUS); > -} > - > -static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) > -{ > - u32 forcewake_ack; > - > - if (IS_HASWELL(dev_priv->dev)) > - forcewake_ack = FORCEWAKE_ACK_HSW; > - else > - forcewake_ack = FORCEWAKE_MT_ACK; > - > - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0, > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > - > - I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > - /* something from same cacheline, but !FORCEWAKE_MT */ > - POSTING_READ(ECOBUS); > - > - if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL), > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); > - > - /* WaRsForcewakeWaitTC0:ivb,hsw */ > - __gen6_gt_wait_for_thread_c0(dev_priv); > -} > - > -/* > - * Generally this is called implicitly by the register read function. However, > - * if some sequence requires the GT to not power down then this function should > - * be called at the beginning of the sequence followed by a call to > - * gen6_gt_force_wake_put() at the end of the sequence. > - */ > -void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > -{ > - unsigned long irqflags; > - > - spin_lock_irqsave(&dev_priv->gt_lock, irqflags); > - if (dev_priv->forcewake_count++ == 0) > - dev_priv->gt.force_wake_get(dev_priv); > - spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); > -} > - > -void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) > -{ > - u32 gtfifodbg; > - gtfifodbg = I915_READ_NOTRACE(GTFIFODBG); > - if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK, > - "MMIO read or write has been dropped %x\n", gtfifodbg)) > - I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK); > -} > - > -static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE, 0); > - /* something from same cacheline, but !FORCEWAKE */ > - POSTING_READ(ECOBUS); > - gen6_gt_check_fifodbg(dev_priv); > -} > - > -static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > - /* something from same cacheline, but !FORCEWAKE_MT */ > - POSTING_READ(ECOBUS); > - gen6_gt_check_fifodbg(dev_priv); > -} > - > -/* > - * see gen6_gt_force_wake_get() > - */ > -void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > -{ > - unsigned long irqflags; > - > - spin_lock_irqsave(&dev_priv->gt_lock, irqflags); > - if (--dev_priv->forcewake_count == 0) > - dev_priv->gt.force_wake_put(dev_priv); > - spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); > -} > - > -int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) > -{ > - int ret = 0; > - > - if (dev_priv->gt_fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { > - int loop = 500; > - u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > - while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) { > - udelay(10); > - fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > - } > - if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES)) > - ++ret; > - dev_priv->gt_fifo_count = fifo; > - } > - dev_priv->gt_fifo_count--; > - > - return ret; > -} > - > -static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff)); > - /* something from same cacheline, but !FORCEWAKE_VLV */ > - POSTING_READ(FORCEWAKE_ACK_VLV); > -} > - > -static void vlv_force_wake_get(struct drm_i915_private *dev_priv) > -{ > - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > - > - I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > - I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, > - _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > - > - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); > - > - if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) & > - FORCEWAKE_KERNEL), > - FORCEWAKE_ACK_TIMEOUT_MS)) > - DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); > - > - /* WaRsForcewakeWaitTC0:vlv */ > - __gen6_gt_wait_for_thread_c0(dev_priv); > -} > - > -static void vlv_force_wake_put(struct drm_i915_private *dev_priv) > -{ > - I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > - I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, > - _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > - /* The below doubles as a POSTING_READ */ > - gen6_gt_check_fifodbg(dev_priv); > -} > - > -void intel_gt_reset(struct drm_device *dev) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - > - if (IS_VALLEYVIEW(dev)) { > - vlv_force_wake_reset(dev_priv); > - } else if (INTEL_INFO(dev)->gen >= 6) { > - __gen6_gt_force_wake_reset(dev_priv); > - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) > - __gen6_gt_force_wake_mt_reset(dev_priv); > - } > -} > - > -void intel_gt_init(struct drm_device *dev) > -{ > - struct drm_i915_private *dev_priv = dev->dev_private; > - > - spin_lock_init(&dev_priv->gt_lock); > - > - intel_gt_reset(dev); > - > - if (IS_VALLEYVIEW(dev)) { > - dev_priv->gt.force_wake_get = vlv_force_wake_get; > - dev_priv->gt.force_wake_put = vlv_force_wake_put; > - } else if (IS_HASWELL(dev)) { > - dev_priv->gt.force_wake_get = __gen6_gt_force_wake_mt_get; > - dev_priv->gt.force_wake_put = __gen6_gt_force_wake_mt_put; > - } else if (IS_IVYBRIDGE(dev)) { > - u32 ecobus; > - > - /* IVB configs may use multi-threaded forcewake */ > - > - /* A small trick here - if the bios hasn't configured > - * MT forcewake, and if the device is in RC6, then > - * force_wake_mt_get will not wake the device and the > - * ECOBUS read will return zero. Which will be > - * (correctly) interpreted by the test below as MT > - * forcewake being disabled. > - */ > - mutex_lock(&dev->struct_mutex); > - __gen6_gt_force_wake_mt_get(dev_priv); > - ecobus = I915_READ_NOTRACE(ECOBUS); > - __gen6_gt_force_wake_mt_put(dev_priv); > - mutex_unlock(&dev->struct_mutex); > - > - if (ecobus & FORCEWAKE_MT_ENABLE) { > - dev_priv->gt.force_wake_get = > - __gen6_gt_force_wake_mt_get; > - dev_priv->gt.force_wake_put = > - __gen6_gt_force_wake_mt_put; > - } else { > - DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); > - DRM_INFO("when using vblank-synced partial screen updates.\n"); > - dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; > - dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; > - } > - } else if (IS_GEN6(dev)) { > - dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get; > - dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put; > - } > - INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, > - intel_gen6_powersave_work); > -} > - > int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) > { > WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); > @@ -5634,3 +5384,11 @@ int vlv_freq_opcode(int ddr_freq, int val) > return val; > } > > +void intel_pm_init(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work, > + intel_gen6_powersave_work); > +} > + > diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c > new file mode 100644 > index 0000000..8c2f460 > --- /dev/null > +++ b/drivers/gpu/drm/i915/intel_uncore.c > @@ -0,0 +1,569 @@ > +/* > + * Copyright ? 2013 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > + * IN THE SOFTWARE. > + */ > + > +#include "i915_drv.h" > +#include "intel_drv.h" > + > +#define FORCEWAKE_ACK_TIMEOUT_MS 2 > + > +static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) > +{ > + u32 gt_thread_status_mask; > + > + if (IS_HASWELL(dev_priv->dev)) > + gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK_HSW; > + else > + gt_thread_status_mask = GEN6_GT_THREAD_STATUS_CORE_MASK; > + > + /* w/a for a sporadic read returning 0 by waiting for the GT > + * thread to wake up. > + */ > + if (wait_for_atomic_us((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500)) > + DRM_ERROR("GT thread status wait timed out\n"); > +} > + > +static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE, 0); > + POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ > +} > + > +static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > +{ > + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1) == 0, > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > + > + I915_WRITE_NOTRACE(FORCEWAKE, 1); > + POSTING_READ(ECOBUS); /* something from same cacheline, but !FORCEWAKE */ > + > + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK) & 1), > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); > + > + /* WaRsForcewakeWaitTC0:snb */ > + __gen6_gt_wait_for_thread_c0(dev_priv); > +} > + > +static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff)); > + /* something from same cacheline, but !FORCEWAKE_MT */ > + POSTING_READ(ECOBUS); > +} > + > +static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) > +{ > + u32 forcewake_ack; > + > + if (IS_HASWELL(dev_priv->dev)) > + forcewake_ack = FORCEWAKE_ACK_HSW; > + else > + forcewake_ack = FORCEWAKE_MT_ACK; > + > + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL) == 0, > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > + > + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > + /* something from same cacheline, but !FORCEWAKE_MT */ > + POSTING_READ(ECOBUS); > + > + if (wait_for_atomic((I915_READ_NOTRACE(forcewake_ack) & FORCEWAKE_KERNEL), > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for forcewake to ack request.\n"); > + > + /* WaRsForcewakeWaitTC0:ivb,hsw */ > + __gen6_gt_wait_for_thread_c0(dev_priv); > +} > + > +static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv) > +{ > + u32 gtfifodbg; > + gtfifodbg = I915_READ_NOTRACE(GTFIFODBG); > + if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK, > + "MMIO read or write has been dropped %x\n", gtfifodbg)) > + I915_WRITE_NOTRACE(GTFIFODBG, GT_FIFO_CPU_ERROR_MASK); > +} > + > +static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE, 0); > + /* something from same cacheline, but !FORCEWAKE */ > + POSTING_READ(ECOBUS); > + gen6_gt_check_fifodbg(dev_priv); > +} > + > +static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > + /* something from same cacheline, but !FORCEWAKE_MT */ > + POSTING_READ(ECOBUS); > + gen6_gt_check_fifodbg(dev_priv); > +} > + > +static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) > +{ > + int ret = 0; > + > + if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { > + int loop = 500; > + u32 fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > + while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) { > + udelay(10); > + fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > + } > + if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES)) > + ++ret; > + dev_priv->uncore.fifo_count = fifo; > + } > + dev_priv->uncore.fifo_count--; > + > + return ret; > +} > + > +static void vlv_force_wake_reset(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(0xffff)); > + /* something from same cacheline, but !FORCEWAKE_VLV */ > + POSTING_READ(FORCEWAKE_ACK_VLV); > +} > + > +static void vlv_force_wake_get(struct drm_i915_private *dev_priv) > +{ > + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0, > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n"); > + > + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, > + _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL)); > + > + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL), > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n"); > + > + if (wait_for_atomic((I915_READ_NOTRACE(FORCEWAKE_ACK_MEDIA_VLV) & > + FORCEWAKE_KERNEL), > + FORCEWAKE_ACK_TIMEOUT_MS)) > + DRM_ERROR("Timed out waiting for media to ack forcewake request.\n"); > + > + /* WaRsForcewakeWaitTC0:vlv */ > + __gen6_gt_wait_for_thread_c0(dev_priv); > +} > + > +static void vlv_force_wake_put(struct drm_i915_private *dev_priv) > +{ > + I915_WRITE_NOTRACE(FORCEWAKE_VLV, _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > + I915_WRITE_NOTRACE(FORCEWAKE_MEDIA_VLV, > + _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL)); > + /* The below doubles as a POSTING_READ */ > + gen6_gt_check_fifodbg(dev_priv); > +} > + > +void intel_uncore_early_sanitize(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (HAS_FPGA_DBG_UNCLAIMED(dev)) > + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > +} > + > +void intel_uncore_init(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + spin_lock_init(&dev_priv->uncore.lock); > + > + intel_uncore_reset(dev); > + > + if (IS_VALLEYVIEW(dev)) { > + dev_priv->uncore.funcs.force_wake_get = vlv_force_wake_get; > + dev_priv->uncore.funcs.force_wake_put = vlv_force_wake_put; > + } else if (IS_HASWELL(dev)) { > + dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get; > + dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put; > + } else if (IS_IVYBRIDGE(dev)) { > + u32 ecobus; > + > + /* IVB configs may use multi-threaded forcewake */ > + > + /* A small trick here - if the bios hasn't configured > + * MT forcewake, and if the device is in RC6, then > + * force_wake_mt_get will not wake the device and the > + * ECOBUS read will return zero. Which will be > + * (correctly) interpreted by the test below as MT > + * forcewake being disabled. > + */ > + mutex_lock(&dev->struct_mutex); > + __gen6_gt_force_wake_mt_get(dev_priv); > + ecobus = I915_READ_NOTRACE(ECOBUS); > + __gen6_gt_force_wake_mt_put(dev_priv); > + mutex_unlock(&dev->struct_mutex); > + > + if (ecobus & FORCEWAKE_MT_ENABLE) { > + dev_priv->uncore.funcs.force_wake_get = > + __gen6_gt_force_wake_mt_get; > + dev_priv->uncore.funcs.force_wake_put = > + __gen6_gt_force_wake_mt_put; > + } else { > + DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n"); > + DRM_INFO("when using vblank-synced partial screen updates.\n"); > + dev_priv->uncore.funcs.force_wake_get = > + __gen6_gt_force_wake_get; > + dev_priv->uncore.funcs.force_wake_put = > + __gen6_gt_force_wake_put; > + } > + } else if (IS_GEN6(dev)) { > + dev_priv->uncore.funcs.force_wake_get = > + __gen6_gt_force_wake_get; > + dev_priv->uncore.funcs.force_wake_put = > + __gen6_gt_force_wake_put; > + } > +} > + > +void intel_uncore_reset(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (IS_VALLEYVIEW(dev)) { > + vlv_force_wake_reset(dev_priv); > + } else if (INTEL_INFO(dev)->gen >= 6) { > + __gen6_gt_force_wake_reset(dev_priv); > + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) > + __gen6_gt_force_wake_mt_reset(dev_priv); > + } > +} > + > +/* > + * Generally this is called implicitly by the register read function. However, > + * if some sequence requires the GT to not power down then this function should > + * be called at the beginning of the sequence followed by a call to > + * gen6_gt_force_wake_put() at the end of the sequence. > + */ > +void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) > +{ > + unsigned long irqflags; > + > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > + if (dev_priv->uncore.forcewake_count++ == 0) > + dev_priv->uncore.funcs.force_wake_get(dev_priv); > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > +} > + > +/* > + * see gen6_gt_force_wake_get() > + */ > +void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) > +{ > + unsigned long irqflags; > + > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > + if (--dev_priv->uncore.forcewake_count == 0) > + dev_priv->uncore.funcs.force_wake_put(dev_priv); > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > +} > + > +/* We give fast paths for the really cool registers */ > +#define NEEDS_FORCE_WAKE(dev_priv, reg) \ > + ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ > + ((reg) < 0x40000) && \ > + ((reg) != FORCEWAKE)) > + > +static void > +ilk_dummy_write(struct drm_i915_private *dev_priv) > +{ > + /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up > + * the chip from rc6 before touching it for real. MI_MODE is masked, > + * hence harmless to write 0 into. */ > + I915_WRITE_NOTRACE(MI_MODE, 0); > +} > + > +static void > +hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg) > +{ > + if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && > + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > + DRM_ERROR("Unknown unclaimed register before writing to %x\n", > + reg); > + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > + } > +} > + > +static void > +hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) > +{ > + if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) && > + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > + DRM_ERROR("Unclaimed write to %x\n", reg); > + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > + } > +} > + > +#define __i915_read(x, y) \ > +u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ > + u##x val = 0; \ > + if (IS_GEN5(dev_priv->dev)) \ > + ilk_dummy_write(dev_priv); \ > + if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ > + unsigned long irqflags; \ > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); \ > + if (dev_priv->uncore.forcewake_count == 0) \ > + dev_priv->uncore.funcs.force_wake_get(dev_priv); \ > + val = read##y(dev_priv->regs + reg); \ > + if (dev_priv->uncore.forcewake_count == 0) \ > + dev_priv->uncore.funcs.force_wake_put(dev_priv); \ > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ > + } else { \ > + val = read##y(dev_priv->regs + reg); \ > + } \ > + trace_i915_reg_rw(false, reg, val, sizeof(val)); \ > + return val; \ > +} > + > +__i915_read(8, b) > +__i915_read(16, w) > +__i915_read(32, l) > +__i915_read(64, q) > +#undef __i915_read > + > +#define __i915_write(x, y) \ > +void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ > + u32 __fifo_ret = 0; \ > + trace_i915_reg_rw(true, reg, val, sizeof(val)); \ > + if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ > + __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ > + } \ > + if (IS_GEN5(dev_priv->dev)) \ > + ilk_dummy_write(dev_priv); \ > + hsw_unclaimed_reg_clear(dev_priv, reg); \ > + write##y(val, dev_priv->regs + reg); \ > + if (unlikely(__fifo_ret)) { \ > + gen6_gt_check_fifodbg(dev_priv); \ > + } \ > + hsw_unclaimed_reg_check(dev_priv, reg); \ > +} > +__i915_write(8, b) > +__i915_write(16, w) > +__i915_write(32, l) > +__i915_write(64, q) > +#undef __i915_write > + > +static const struct register_whitelist { > + uint64_t offset; > + uint32_t size; > + uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ > +} whitelist[] = { > + { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 }, > +}; > + > +int i915_reg_read_ioctl(struct drm_device *dev, > + void *data, struct drm_file *file) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + struct drm_i915_reg_read *reg = data; > + struct register_whitelist const *entry = whitelist; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) { > + if (entry->offset == reg->offset && > + (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask)) > + break; > + } > + > + if (i == ARRAY_SIZE(whitelist)) > + return -EINVAL; > + > + switch (entry->size) { > + case 8: > + reg->val = I915_READ64(reg->offset); > + break; > + case 4: > + reg->val = I915_READ(reg->offset); > + break; > + case 2: > + reg->val = I915_READ16(reg->offset); > + break; > + case 1: > + reg->val = I915_READ8(reg->offset); > + break; > + default: > + WARN_ON(1); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int i8xx_do_reset(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (IS_I85X(dev)) > + return -ENODEV; > + > + I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830); > + POSTING_READ(D_STATE); > + > + if (IS_I830(dev) || IS_845G(dev)) { > + I915_WRITE(DEBUG_RESET_I830, > + DEBUG_RESET_DISPLAY | > + DEBUG_RESET_RENDER | > + DEBUG_RESET_FULL); > + POSTING_READ(DEBUG_RESET_I830); > + msleep(1); > + > + I915_WRITE(DEBUG_RESET_I830, 0); > + POSTING_READ(DEBUG_RESET_I830); > + } > + > + msleep(1); > + > + I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830); > + POSTING_READ(D_STATE); > + > + return 0; > +} > + > +static int i965_reset_complete(struct drm_device *dev) > +{ > + u8 gdrst; > + pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst); > + return (gdrst & GRDOM_RESET_ENABLE) == 0; > +} > + > +static int i965_do_reset(struct drm_device *dev) > +{ > + int ret; > + > + /* > + * Set the domains we want to reset (GRDOM/bits 2 and 3) as > + * well as the reset bit (GR/bit 0). Setting the GR bit > + * triggers the reset; when done, the hardware will clear it. > + */ > + pci_write_config_byte(dev->pdev, I965_GDRST, > + GRDOM_RENDER | GRDOM_RESET_ENABLE); > + ret = wait_for(i965_reset_complete(dev), 500); > + if (ret) > + return ret; > + > + /* We can't reset render&media without also resetting display ... */ > + pci_write_config_byte(dev->pdev, I965_GDRST, > + GRDOM_MEDIA | GRDOM_RESET_ENABLE); > + > + ret = wait_for(i965_reset_complete(dev), 500); > + if (ret) > + return ret; > + > + pci_write_config_byte(dev->pdev, I965_GDRST, 0); > + > + return 0; > +} > + > +static int ironlake_do_reset(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + u32 gdrst; > + int ret; > + > + gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); > + gdrst &= ~GRDOM_MASK; > + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, > + gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE); > + ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); > + if (ret) > + return ret; > + > + /* We can't reset render&media without also resetting display ... */ > + gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR); > + gdrst &= ~GRDOM_MASK; > + I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, > + gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE); > + return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500); > +} > + > +static int gen6_do_reset(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + int ret; > + unsigned long irqflags; > + > + /* Hold uncore.lock across reset to prevent any register access > + * with forcewake not set correctly > + */ > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); > + > + /* Reset the chip */ > + > + /* GEN6_GDRST is not in the gt power well, no need to check > + * for fifo space for the write or forcewake the chip for > + * the read > + */ > + I915_WRITE_NOTRACE(GEN6_GDRST, GEN6_GRDOM_FULL); > + > + /* Spin waiting for the device to ack the reset request */ > + ret = wait_for((I915_READ_NOTRACE(GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); > + > + /* If reset with a user forcewake, try to restore, otherwise turn it off */ > + if (dev_priv->uncore.forcewake_count) > + dev_priv->uncore.funcs.force_wake_get(dev_priv); > + else > + dev_priv->uncore.funcs.force_wake_put(dev_priv); > + > + /* Restore fifo count */ > + dev_priv->uncore.fifo_count = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); > + > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); > + return ret; > +} > + > +int intel_gpu_reset(struct drm_device *dev) > +{ > + switch (INTEL_INFO(dev)->gen) { > + case 7: > + case 6: return gen6_do_reset(dev); > + case 5: return ironlake_do_reset(dev); > + case 4: return i965_do_reset(dev); > + case 2: return i8xx_do_reset(dev); > + default: return -ENODEV; > + } > +} > + > +void intel_uncore_clear_errors(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (HAS_FPGA_DBG_UNCLAIMED(dev)) > + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > +} > + > +void intel_uncore_check_errors(struct drm_device *dev) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + > + if (HAS_FPGA_DBG_UNCLAIMED(dev) && > + (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) { > + DRM_ERROR("Unclaimed register before interrupt\n"); > + I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM); > + } > +} > -- > 1.8.3.2 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx -- Ben Widawsky, Intel Open Source Technology Center