[Intel-gfx] [PATCH 1/6] drm/i915: Colocate all GT access routines in the same file
Ben Widawsky
ben at bwidawsk.net
Sun Jul 14 21:42:49 CEST 2013
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
More information about the Intel-gfx
mailing list