Merge remote-tracking branch 'origin/master' into drm-next
authorDave Airlie <airlied@redhat.com>
Thu, 22 Jan 2015 00:44:41 +0000 (10:44 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 22 Jan 2015 00:44:41 +0000 (10:44 +1000)
Backmerge Linus tree after rc5 + drm-fixes went in.

There were a few amdkfd conflicts I wanted to avoid,
and Ben requested this for nouveau also.

Conflicts:
drivers/gpu/drm/amd/amdkfd/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/radeon/radeon_kfd.c

20 files changed:
1  2 
MAINTAINERS
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/radeon_kfd.c

diff --combined MAINTAINERS
index 23fa31dc9390369fe8dff359fe0dffd2f1fea558,93409ade65a5b15198a1b7de256360ed8130b5a9..aa97dffe59e1b1e6159d3c042bf1fd1ed0135240
@@@ -624,8 -624,6 +624,8 @@@ L:      dri-devel@lists.freedesktop.or
  T:      git git://people.freedesktop.org/~gabbayo/linux.git
  S:      Supported
  F:      drivers/gpu/drm/amd/amdkfd/
 +F:    drivers/gpu/drm/amd/include/cik_structs.h
 +F:    drivers/gpu/drm/amd/include/kgd_kfd_interface.h
  F:      drivers/gpu/drm/radeon/radeon_kfd.c
  F:      drivers/gpu/drm/radeon/radeon_kfd.h
  F:      include/uapi/linux/kfd_ioctl.h
@@@ -726,15 -724,15 +726,15 @@@ F:      include/uapi/linux/apm_bios.
  F:    drivers/char/apm-emulation.c
  
  APPLE BCM5974 MULTITOUCH DRIVER
- M:    Henrik Rydberg <rydberg@euromail.se>
+ M:    Henrik Rydberg <rydberg@bitmath.org>
  L:    linux-input@vger.kernel.org
- S:    Maintained
+ S:    Odd fixes
  F:    drivers/input/mouse/bcm5974.c
  
  APPLE SMC DRIVER
- M:    Henrik Rydberg <rydberg@euromail.se>
+ M:    Henrik Rydberg <rydberg@bitmath.org>
  L:    lm-sensors@lm-sensors.org
- S:    Maintained
+ S:    Odd fixes
  F:    drivers/hwmon/applesmc.c
  
  APPLETALK NETWORK LAYER
@@@ -756,13 -754,6 +756,6 @@@ L:        linux-media@vger.kernel.or
  S:    Maintained
  F:    drivers/media/i2c/aptina-pll.*
  
- ARASAN COMPACT FLASH PATA CONTROLLER
- M:    Viresh Kumar <viresh.linux@gmail.com>
- L:    linux-ide@vger.kernel.org
- S:    Maintained
- F:    include/linux/pata_arasan_cf_data.h
- F:    drivers/ata/pata_arasan_cf.c
  ARC FRAMEBUFFER DRIVER
  M:    Jaya Kumar <jayalk@intworks.biz>
  S:    Maintained
@@@ -2261,6 -2252,7 +2254,7 @@@ F:      drivers/gpio/gpio-bt8xx.
  BTRFS FILE SYSTEM
  M:    Chris Mason <clm@fb.com>
  M:    Josef Bacik <jbacik@fb.com>
+ M:    David Sterba <dsterba@suse.cz>
  L:    linux-btrfs@vger.kernel.org
  W:    http://btrfs.wiki.kernel.org/
  Q:    http://patchwork.kernel.org/project/linux-btrfs/list/
@@@ -2347,7 -2339,8 +2341,8 @@@ CAN NETWORK LAYE
  M:    Oliver Hartkopp <socketcan@hartkopp.net>
  L:    linux-can@vger.kernel.org
  W:    http://gitorious.org/linux-can
- T:    git git://gitorious.org/linux-can/linux-can-next.git
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
  S:    Maintained
  F:    Documentation/networking/can.txt
  F:    net/can/
@@@ -2362,7 -2355,8 +2357,8 @@@ M:      Wolfgang Grandegger <wg@grandegger.c
  M:    Marc Kleine-Budde <mkl@pengutronix.de>
  L:    linux-can@vger.kernel.org
  W:    http://gitorious.org/linux-can
- T:    git git://gitorious.org/linux-can/linux-can-next.git
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
  S:    Maintained
  F:    drivers/net/can/
  F:    include/linux/can/dev.h
@@@ -3184,7 -3178,7 +3180,7 @@@ L:      dmaengine@vger.kernel.or
  Q:    https://patchwork.kernel.org/project/linux-dmaengine/list/
  S:    Maintained
  F:    drivers/dma/
- F:    include/linux/dma*
+ F:    include/linux/dmaengine.h
  F:    Documentation/dmaengine/
  T:    git git://git.infradead.org/users/vkoul/slave-dma.git
  
@@@ -4750,7 -4744,7 +4746,7 @@@ S:      Supporte
  F:    drivers/scsi/ipr.*
  
  IBM Power Virtual Ethernet Device Driver
- M:    Santiago Leon <santil@linux.vnet.ibm.com>
+ M:    Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
  L:    netdev@vger.kernel.org
  S:    Supported
  F:    drivers/net/ethernet/ibm/ibmveth.*
@@@ -4931,7 -4925,6 +4927,6 @@@ F:      include/uapi/linux/inotify.
  
  INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
  M:    Dmitry Torokhov <dmitry.torokhov@gmail.com>
- M:    Dmitry Torokhov <dtor@mail.ru>
  L:    linux-input@vger.kernel.org
  Q:    http://patchwork.kernel.org/project/linux-input/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
@@@ -4942,10 -4935,10 +4937,10 @@@ F:   include/uapi/linux/input.
  F:    include/linux/input/
  
  INPUT MULTITOUCH (MT) PROTOCOL
- M:    Henrik Rydberg <rydberg@euromail.se>
+ M:    Henrik Rydberg <rydberg@bitmath.org>
  L:    linux-input@vger.kernel.org
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
- S:    Maintained
+ S:    Odd fixes
  F:    Documentation/input/multi-touch-protocol.txt
  F:    drivers/input/input-mt.c
  K:    \b(ABS|SYN)_MT_
@@@ -5281,6 -5274,15 +5276,15 @@@ W:    www.open-iscsi.or
  Q:    http://patchwork.kernel.org/project/linux-rdma/list/
  F:    drivers/infiniband/ulp/iser/
  
+ ISCSI EXTENSIONS FOR RDMA (ISER) TARGET
+ M:    Sagi Grimberg <sagig@mellanox.com>
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
+ L:    linux-rdma@vger.kernel.org
+ L:    target-devel@vger.kernel.org
+ S:    Supported
+ W:    http://www.linux-iscsi.org
+ F:    drivers/infiniband/ulp/isert
  ISDN SUBSYSTEM
  M:    Karsten Keil <isdn@linux-pingi.de>
  L:    isdn4linux@listserv.isdn4linux.de (subscribers-only)
@@@ -5695,6 -5697,49 +5699,49 @@@ F:    drivers/lguest
  F:    include/linux/lguest*.h
  F:    tools/lguest/
  
+ LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
+ M:    Tejun Heo <tj@kernel.org>
+ L:    linux-ide@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+ S:    Maintained
+ F:    drivers/ata/
+ F:    include/linux/ata.h
+ F:    include/linux/libata.h
+ LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
+ M:    Viresh Kumar <viresh.linux@gmail.com>
+ L:    linux-ide@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+ S:    Maintained
+ F:    include/linux/pata_arasan_cf_data.h
+ F:    drivers/ata/pata_arasan_cf.c
+ LIBATA PATA DRIVERS
+ M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+ M:    Tejun Heo <tj@kernel.org>
+ L:    linux-ide@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+ S:    Maintained
+ F:    drivers/ata/pata_*.c
+ F:    drivers/ata/ata_generic.c
+ LIBATA SATA AHCI PLATFORM devices support
+ M:    Hans de Goede <hdegoede@redhat.com>
+ M:    Tejun Heo <tj@kernel.org>
+ L:    linux-ide@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+ S:    Maintained
+ F:    drivers/ata/ahci_platform.c
+ F:    drivers/ata/libahci_platform.c
+ F:    include/linux/ahci_platform.h
+ LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
+ M:    Mikael Pettersson <mikpelinux@gmail.com>
+ L:    linux-ide@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+ S:    Maintained
+ F:    drivers/ata/sata_promise.*
  LIBLOCKDEP
  M:    Sasha Levin <sasha.levin@oracle.com>
  S:    Maintained
@@@ -7401,6 -7446,7 +7448,7 @@@ F:      drivers/crypto/picoxcell
  PIN CONTROL SUBSYSTEM
  M:    Linus Walleij <linus.walleij@linaro.org>
  L:    linux-gpio@vger.kernel.org
+ T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
  S:    Maintained
  F:    drivers/pinctrl/
  F:    include/linux/pinctrl/
@@@ -7568,12 -7614,6 +7616,6 @@@ W:     http://wireless.kernel.org/en/users/
  S:    Obsolete
  F:    drivers/net/wireless/prism54/
  
- PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
- M:    Mikael Pettersson <mikpelinux@gmail.com>
- L:    linux-ide@vger.kernel.org
- S:    Maintained
- F:    drivers/ata/sata_promise.*
  PS3 NETWORK SUPPORT
  M:    Geoff Levand <geoff@infradead.org>
  L:    netdev@vger.kernel.org
@@@ -7739,8 -7779,7 +7781,7 @@@ F:      Documentation/scsi/LICENSE.qla2xx
  F:    drivers/scsi/qla2xxx/
  
  QLOGIC QLA4XXX iSCSI DRIVER
- M:    Vikas Chaudhary <vikas.chaudhary@qlogic.com>
- M:    iscsi-driver@qlogic.com
+ M:    QLogic-Storage-Upstream@qlogic.com
  L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    Documentation/scsi/LICENSE.qla4xxx
@@@ -8548,25 -8587,6 +8589,6 @@@ S:     Maintaine
  F:    drivers/misc/phantom.c
  F:    include/uapi/linux/phantom.h
  
- SERIAL ATA (SATA) SUBSYSTEM
- M:    Tejun Heo <tj@kernel.org>
- L:    linux-ide@vger.kernel.org
- T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
- S:    Supported
- F:    drivers/ata/
- F:    include/linux/ata.h
- F:    include/linux/libata.h
- SERIAL ATA AHCI PLATFORM devices support
- M:    Hans de Goede <hdegoede@redhat.com>
- M:    Tejun Heo <tj@kernel.org>
- L:    linux-ide@vger.kernel.org
- T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
- S:    Supported
- F:    drivers/ata/ahci_platform.c
- F:    drivers/ata/libahci_platform.c
- F:    include/linux/ahci_platform.h
  SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
  M:    Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
  L:    linux-scsi@vger.kernel.org
@@@ -9535,7 -9555,8 +9557,8 @@@ F:      drivers/platform/x86/thinkpad_acpi.
  TI BANDGAP AND THERMAL DRIVER
  M:    Eduardo Valentin <edubezval@gmail.com>
  L:    linux-pm@vger.kernel.org
- S:    Supported
+ L:    linux-omap@vger.kernel.org
+ S:    Maintained
  F:    drivers/thermal/ti-soc-thermal/
  
  TI CLOCK DRIVER
diff --combined drivers/gpu/drm/Makefile
index 9d92ba3ff10ca32b771907a9bbac35e99c180999,e620807418ea7559eddc9d5a994a0c5e1f829a9c..cf0eed8208b53ef352a360994a623f557a4bc8c9
@@@ -37,6 -37,7 +37,7 @@@ obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_
  obj-$(CONFIG_DRM_TTM) += ttm/
  obj-$(CONFIG_DRM_TDFX)        += tdfx/
  obj-$(CONFIG_DRM_R128)        += r128/
+ obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
  obj-$(CONFIG_DRM_RADEON)+= radeon/
  obj-$(CONFIG_DRM_MGA) += mga/
  obj-$(CONFIG_DRM_I810)        += i810/
@@@ -54,7 -55,6 +55,7 @@@ obj-$(CONFIG_DRM_GMA500) += gma500
  obj-$(CONFIG_DRM_UDL) += udl/
  obj-$(CONFIG_DRM_AST) += ast/
  obj-$(CONFIG_DRM_ARMADA) += armada/
 +obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
  obj-$(CONFIG_DRM_OMAP)        += omapdrm/
@@@ -68,4 -68,3 +69,3 @@@ obj-$(CONFIG_DRM_IMX) += imx
  obj-y                 += i2c/
  obj-y                 += panel/
  obj-y                 += bridge/
- obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
index cd09c05ee7e4bcdbaf6b2d9f24f448fa1610ef06,307a309110e60d5f473be86d26c24e3b0cb80a90..0f4960148126d96adb7cbdf9432da533428c4080
@@@ -7,11 -7,7 +7,10 @@@ ccflags-y := -Iinclude/drm -Idrivers/gp
  amdkfd-y      := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
                kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
                kfd_process.o kfd_queue.o kfd_mqd_manager.o \
 -              kfd_kernel_queue.o kfd_packet_manager.o \
 -              kfd_process_queue_manager.o kfd_device_queue_manager.o
 +              kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \
 +              kfd_kernel_queue.o kfd_kernel_queue_cik.o \
 +              kfd_kernel_queue_vi.o kfd_packet_manager.o \
 +              kfd_process_queue_manager.o kfd_device_queue_manager.o \
 +              kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \
-               kfd_interrupt.o
  
  obj-$(CONFIG_HSA_AMD) += amdkfd.o
index 38b6150a19eeb5cad10ed9dcb3033aeb8cb61355,fcfdf23e1913ed01663b46bebfda5eec8bc4079d..732087dcac914bf88bf5b6e9e244ac92922ba568
@@@ -31,7 -31,6 +31,6 @@@
  #include <uapi/linux/kfd_ioctl.h>
  #include <linux/time.h>
  #include <linux/mm.h>
- #include <linux/uaccess.h>
  #include <uapi/asm-generic/mman-common.h>
  #include <asm/processor.h>
  #include "kfd_priv.h"
@@@ -127,17 -126,14 +126,14 @@@ static int kfd_open(struct inode *inode
        return 0;
  }
  
- static long kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
-                                       void __user *arg)
+ static int kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
+                                       void *data)
  {
-       struct kfd_ioctl_get_version_args args;
+       struct kfd_ioctl_get_version_args *args = data;
        int err = 0;
  
-       args.major_version = KFD_IOCTL_MAJOR_VERSION;
-       args.minor_version = KFD_IOCTL_MINOR_VERSION;
-       if (copy_to_user(arg, &args, sizeof(args)))
-               err = -EFAULT;
+       args->major_version = KFD_IOCTL_MAJOR_VERSION;
+       args->minor_version = KFD_IOCTL_MINOR_VERSION;
  
        return err;
  }
  static int set_queue_properties_from_user(struct queue_properties *q_properties,
                                struct kfd_ioctl_create_queue_args *args)
  {
 +      void *tmp;
 +
        if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
                pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
                return -EINVAL;
                return -EFAULT;
        }
  
 +      tmp = (void *)(uintptr_t)args->eop_buffer_address;
 +      if (tmp != NULL &&
 +              !access_ok(VERIFY_WRITE, tmp, sizeof(uint32_t))) {
 +              pr_debug("kfd: can't access eop buffer");
 +              return -EFAULT;
 +      }
 +
 +      tmp = (void *)(uintptr_t)args->ctx_save_restore_address;
 +      if (tmp != NULL &&
 +              !access_ok(VERIFY_WRITE, tmp, sizeof(uint32_t))) {
 +              pr_debug("kfd: can't access ctx save restore buffer");
 +              return -EFAULT;
 +      }
 +
        q_properties->is_interop = false;
        q_properties->queue_percent = args->queue_percentage;
        q_properties->priority = args->queue_priority;
        q_properties->queue_size = args->ring_size;
        q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
        q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
 +      q_properties->eop_ring_buffer_address = args->eop_buffer_address;
 +      q_properties->eop_ring_buffer_size = args->eop_buffer_size;
 +      q_properties->ctx_save_restore_area_address =
 +                      args->ctx_save_restore_address;
 +      q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size;
        if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
                args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
                q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
 +      else if (args->queue_type == KFD_IOC_QUEUE_TYPE_SDMA)
 +              q_properties->type = KFD_QUEUE_TYPE_SDMA;
        else
                return -ENOTSUPP;
  
  
        pr_debug("Queue Format (%d)\n", q_properties->format);
  
 +      pr_debug("Queue EOP (0x%llX)\n", q_properties->eop_ring_buffer_address);
 +
 +      pr_debug("Queue CTX save arex (0x%llX)\n",
 +                      q_properties->ctx_save_restore_area_address);
 +
        return 0;
  }
  
- static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
-                                       void __user *arg)
+ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+                                       void *data)
  {
-       struct kfd_ioctl_create_queue_args args;
+       struct kfd_ioctl_create_queue_args *args = data;
        struct kfd_dev *dev;
        int err = 0;
        unsigned int queue_id;
  
        memset(&q_properties, 0, sizeof(struct queue_properties));
  
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
        pr_debug("kfd: creating queue ioctl\n");
  
-       err = set_queue_properties_from_user(&q_properties, &args);
+       err = set_queue_properties_from_user(&q_properties, args);
        if (err)
                return err;
  
-       pr_debug("kfd: looking for gpu id 0x%x\n", args.gpu_id);
-       dev = kfd_device_by_id(args.gpu_id);
++      pr_debug("kfd: looking for gpu id 0x%x\n", args->gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
 -      if (dev == NULL)
 +      if (dev == NULL) {
-               pr_debug("kfd: gpu id 0x%x was not found\n", args.gpu_id);
++              pr_debug("kfd: gpu id 0x%x was not found\n", args->gpu_id);
                return -EINVAL;
 +      }
  
        mutex_lock(&p->mutex);
  
        pdd = kfd_bind_process_to_device(dev, p);
        if (IS_ERR(pdd)) {
-               err = PTR_ERR(pdd);
+               err = -ESRCH;
                goto err_bind_process;
        }
  
                        p->pasid,
                        dev->id);
  
 -      err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0,
 -                              KFD_QUEUE_TYPE_COMPUTE, &queue_id);
 +      err = pqm_create_queue(&p->pqm, dev, filep, &q_properties,
 +                              0, q_properties.type, &queue_id);
        if (err != 0)
                goto err_create_queue;
  
-       args.queue_id = queue_id;
+       args->queue_id = queue_id;
  
        /* Return gpu_id as doorbell offset for mmap usage */
-       args.doorbell_offset = args.gpu_id << PAGE_SHIFT;
-       if (copy_to_user(arg, &args, sizeof(args))) {
-               err = -EFAULT;
-               goto err_copy_args_out;
-       }
+       args->doorbell_offset = args->gpu_id << PAGE_SHIFT;
  
        mutex_unlock(&p->mutex);
  
-       pr_debug("kfd: queue id %d was created successfully\n", args.queue_id);
+       pr_debug("kfd: queue id %d was created successfully\n", args->queue_id);
  
        pr_debug("ring buffer address == 0x%016llX\n",
-                       args.ring_base_address);
+                       args->ring_base_address);
  
        pr_debug("read ptr address    == 0x%016llX\n",
-                       args.read_pointer_address);
+                       args->read_pointer_address);
  
        pr_debug("write ptr address   == 0x%016llX\n",
-                       args.write_pointer_address);
+                       args->write_pointer_address);
  
        return 0;
  
- err_copy_args_out:
-       pqm_destroy_queue(&p->pqm, queue_id);
  err_create_queue:
  err_bind_process:
        mutex_unlock(&p->mutex);
  }
  
  static int kfd_ioctl_destroy_queue(struct file *filp, struct kfd_process *p,
-                                       void __user *arg)
+                                       void *data)
  {
        int retval;
-       struct kfd_ioctl_destroy_queue_args args;
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
+       struct kfd_ioctl_destroy_queue_args *args = data;
  
        pr_debug("kfd: destroying queue id %d for PASID %d\n",
-                               args.queue_id,
+                               args->queue_id,
                                p->pasid);
  
        mutex_lock(&p->mutex);
  
-       retval = pqm_destroy_queue(&p->pqm, args.queue_id);
+       retval = pqm_destroy_queue(&p->pqm, args->queue_id);
  
        mutex_unlock(&p->mutex);
        return retval;
  }
  
  static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p,
-                                       void __user *arg)
+                                       void *data)
  {
        int retval;
-       struct kfd_ioctl_update_queue_args args;
+       struct kfd_ioctl_update_queue_args *args = data;
        struct queue_properties properties;
  
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-       if (args.queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
+       if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
                pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
                return -EINVAL;
        }
  
-       if (args.queue_priority > KFD_MAX_QUEUE_PRIORITY) {
+       if (args->queue_priority > KFD_MAX_QUEUE_PRIORITY) {
                pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
                return -EINVAL;
        }
  
-       if ((args.ring_base_address) &&
+       if ((args->ring_base_address) &&
                (!access_ok(VERIFY_WRITE,
-                       (const void __user *) args.ring_base_address,
+                       (const void __user *) args->ring_base_address,
                        sizeof(uint64_t)))) {
                pr_err("kfd: can't access ring base address\n");
                return -EFAULT;
        }
  
-       if (!is_power_of_2(args.ring_size) && (args.ring_size != 0)) {
+       if (!is_power_of_2(args->ring_size) && (args->ring_size != 0)) {
                pr_err("kfd: ring size must be a power of 2 or 0\n");
                return -EINVAL;
        }
  
-       properties.queue_address = args.ring_base_address;
-       properties.queue_size = args.ring_size;
-       properties.queue_percent = args.queue_percentage;
-       properties.priority = args.queue_priority;
+       properties.queue_address = args->ring_base_address;
+       properties.queue_size = args->ring_size;
+       properties.queue_percent = args->queue_percentage;
+       properties.priority = args->queue_priority;
  
        pr_debug("kfd: updating queue id %d for PASID %d\n",
-                       args.queue_id, p->pasid);
+                       args->queue_id, p->pasid);
  
        mutex_lock(&p->mutex);
  
-       retval = pqm_update_queue(&p->pqm, args.queue_id, &properties);
+       retval = pqm_update_queue(&p->pqm, args->queue_id, &properties);
  
        mutex_unlock(&p->mutex);
  
        return retval;
  }
  
- static long kfd_ioctl_set_memory_policy(struct file *filep,
-                               struct kfd_process *p, void __user *arg)
+ static int kfd_ioctl_set_memory_policy(struct file *filep,
+                                       struct kfd_process *p, void *data)
  {
-       struct kfd_ioctl_set_memory_policy_args args;
+       struct kfd_ioctl_set_memory_policy_args *args = data;
        struct kfd_dev *dev;
        int err = 0;
        struct kfd_process_device *pdd;
        enum cache_policy default_policy, alternate_policy;
  
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-       if (args.default_policy != KFD_IOC_CACHE_POLICY_COHERENT
-           && args.default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+       if (args->default_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args->default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
                return -EINVAL;
        }
  
-       if (args.alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
-           && args.alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+       if (args->alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args->alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
                return -EINVAL;
        }
  
-       dev = kfd_device_by_id(args.gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
  
  
        pdd = kfd_bind_process_to_device(dev, p);
        if (IS_ERR(pdd)) {
-               err = PTR_ERR(pdd);
+               err = -ESRCH;
                goto out;
        }
  
-       default_policy = (args.default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+       default_policy = (args->default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
                         ? cache_policy_coherent : cache_policy_noncoherent;
  
        alternate_policy =
-               (args.alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+               (args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
                   ? cache_policy_coherent : cache_policy_noncoherent;
  
 -      if (!dev->dqm->set_cache_memory_policy(dev->dqm,
 +      if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm,
                                &pdd->qpd,
                                default_policy,
                                alternate_policy,
-                               (void __user *)args.alternate_aperture_base,
-                               args.alternate_aperture_size))
+                               (void __user *)args->alternate_aperture_base,
+                               args->alternate_aperture_size))
                err = -EINVAL;
  
  out:
        return err;
  }
  
- static long kfd_ioctl_get_clock_counters(struct file *filep,
-                               struct kfd_process *p, void __user *arg)
+ static int kfd_ioctl_get_clock_counters(struct file *filep,
+                               struct kfd_process *p, void *data)
  {
-       struct kfd_ioctl_get_clock_counters_args args;
+       struct kfd_ioctl_get_clock_counters_args *args = data;
        struct kfd_dev *dev;
        struct timespec time;
  
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-       dev = kfd_device_by_id(args.gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
  
        /* Reading GPU clock counter from KGD */
-       args.gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
+       args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
  
        /* No access to rdtsc. Using raw monotonic time */
        getrawmonotonic(&time);
-       args.cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
+       args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
  
        get_monotonic_boottime(&time);
-       args.system_clock_counter = (uint64_t)timespec_to_ns(&time);
+       args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
  
        /* Since the counter is in nano-seconds we use 1GHz frequency */
-       args.system_clock_freq = 1000000000;
-       if (copy_to_user(arg, &args, sizeof(args)))
-               return -EFAULT;
+       args->system_clock_freq = 1000000000;
  
        return 0;
  }
  
  
  static int kfd_ioctl_get_process_apertures(struct file *filp,
-                               struct kfd_process *p, void __user *arg)
+                               struct kfd_process *p, void *data)
  {
-       struct kfd_ioctl_get_process_apertures_args args;
+       struct kfd_ioctl_get_process_apertures_args *args = data;
        struct kfd_process_device_apertures *pAperture;
        struct kfd_process_device *pdd;
  
        dev_dbg(kfd_device, "get apertures for PASID %d", p->pasid);
  
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-       args.num_of_nodes = 0;
+       args->num_of_nodes = 0;
  
        mutex_lock(&p->mutex);
  
                /* Run over all pdd of the process */
                pdd = kfd_get_first_process_device_data(p);
                do {
-                       pAperture = &args.process_apertures[args.num_of_nodes];
+                       pAperture =
+                               &args->process_apertures[args->num_of_nodes];
                        pAperture->gpu_id = pdd->dev->id;
                        pAperture->lds_base = pdd->lds_base;
                        pAperture->lds_limit = pdd->lds_limit;
                        pAperture->scratch_limit = pdd->scratch_limit;
  
                        dev_dbg(kfd_device,
-                               "node id %u\n", args.num_of_nodes);
+                               "node id %u\n", args->num_of_nodes);
                        dev_dbg(kfd_device,
                                "gpu id %u\n", pdd->dev->id);
                        dev_dbg(kfd_device,
                        dev_dbg(kfd_device,
                                "scratch_limit %llX\n", pdd->scratch_limit);
  
-                       args.num_of_nodes++;
+                       args->num_of_nodes++;
                } while ((pdd = kfd_get_next_process_device_data(p, pdd)) != NULL &&
-                               (args.num_of_nodes < NUM_OF_SUPPORTED_GPUS));
+                               (args->num_of_nodes < NUM_OF_SUPPORTED_GPUS));
        }
  
        mutex_unlock(&p->mutex);
  
-       if (copy_to_user(arg, &args, sizeof(args)))
-               return -EFAULT;
        return 0;
  }
  
+ #define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
+       [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+ /** Ioctl table */
+ static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_VERSION,
+                       kfd_ioctl_get_version, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_QUEUE,
+                       kfd_ioctl_create_queue, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_DESTROY_QUEUE,
+                       kfd_ioctl_destroy_queue, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_MEMORY_POLICY,
+                       kfd_ioctl_set_memory_policy, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_CLOCK_COUNTERS,
+                       kfd_ioctl_get_clock_counters, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_PROCESS_APERTURES,
+                       kfd_ioctl_get_process_apertures, 0),
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_UPDATE_QUEUE,
+                       kfd_ioctl_update_queue, 0),
+ };
+ #define AMDKFD_CORE_IOCTL_COUNT       ARRAY_SIZE(amdkfd_ioctls)
  static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
  {
        struct kfd_process *process;
-       long err = -EINVAL;
+       amdkfd_ioctl_t *func;
+       const struct amdkfd_ioctl_desc *ioctl = NULL;
+       unsigned int nr = _IOC_NR(cmd);
+       char stack_kdata[128];
+       char *kdata = NULL;
+       unsigned int usize, asize;
+       int retcode = -EINVAL;
  
-       dev_dbg(kfd_device,
-               "ioctl cmd 0x%x (#%d), arg 0x%lx\n",
-               cmd, _IOC_NR(cmd), arg);
+       if (nr >= AMDKFD_CORE_IOCTL_COUNT)
+               goto err_i1;
+       if ((nr >= AMDKFD_COMMAND_START) && (nr < AMDKFD_COMMAND_END)) {
+               u32 amdkfd_size;
+               ioctl = &amdkfd_ioctls[nr];
+               amdkfd_size = _IOC_SIZE(ioctl->cmd);
+               usize = asize = _IOC_SIZE(cmd);
+               if (amdkfd_size > asize)
+                       asize = amdkfd_size;
+               cmd = ioctl->cmd;
+       } else
+               goto err_i1;
+       dev_dbg(kfd_device, "ioctl cmd 0x%x (#%d), arg 0x%lx\n", cmd, nr, arg);
  
        process = kfd_get_process(current);
-       if (IS_ERR(process))
-               return PTR_ERR(process);
+       if (IS_ERR(process)) {
+               dev_dbg(kfd_device, "no process\n");
+               goto err_i1;
+       }
  
-       switch (cmd) {
-       case KFD_IOC_GET_VERSION:
-               err = kfd_ioctl_get_version(filep, process, (void __user *)arg);
-               break;
-       case KFD_IOC_CREATE_QUEUE:
-               err = kfd_ioctl_create_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-       case KFD_IOC_DESTROY_QUEUE:
-               err = kfd_ioctl_destroy_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-       case KFD_IOC_SET_MEMORY_POLICY:
-               err = kfd_ioctl_set_memory_policy(filep, process,
-                                               (void __user *)arg);
-               break;
-       case KFD_IOC_GET_CLOCK_COUNTERS:
-               err = kfd_ioctl_get_clock_counters(filep, process,
-                                               (void __user *)arg);
-               break;
-       case KFD_IOC_GET_PROCESS_APERTURES:
-               err = kfd_ioctl_get_process_apertures(filep, process,
-                                               (void __user *)arg);
-               break;
-       case KFD_IOC_UPDATE_QUEUE:
-               err = kfd_ioctl_update_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-       default:
-               dev_err(kfd_device,
-                       "unknown ioctl cmd 0x%x, arg 0x%lx)\n",
-                       cmd, arg);
-               err = -EINVAL;
-               break;
+       /* Do not trust userspace, use our own definition */
+       func = ioctl->func;
+       if (unlikely(!func)) {
+               dev_dbg(kfd_device, "no function\n");
+               retcode = -EINVAL;
+               goto err_i1;
        }
  
-       if (err < 0)
-               dev_err(kfd_device,
-                       "ioctl error %ld for ioctl cmd 0x%x (#%d)\n",
-                       err, cmd, _IOC_NR(cmd));
+       if (cmd & (IOC_IN | IOC_OUT)) {
+               if (asize <= sizeof(stack_kdata)) {
+                       kdata = stack_kdata;
+               } else {
+                       kdata = kmalloc(asize, GFP_KERNEL);
+                       if (!kdata) {
+                               retcode = -ENOMEM;
+                               goto err_i1;
+                       }
+               }
+               if (asize > usize)
+                       memset(kdata + usize, 0, asize - usize);
+       }
  
-       return err;
+       if (cmd & IOC_IN) {
+               if (copy_from_user(kdata, (void __user *)arg, usize) != 0) {
+                       retcode = -EFAULT;
+                       goto err_i1;
+               }
+       } else if (cmd & IOC_OUT) {
+               memset(kdata, 0, usize);
+       }
+       retcode = func(filep, process, kdata);
+       if (cmd & IOC_OUT)
+               if (copy_to_user((void __user *)arg, kdata, usize) != 0)
+                       retcode = -EFAULT;
+ err_i1:
+       if (!ioctl)
+               dev_dbg(kfd_device, "invalid ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n",
+                         task_pid_nr(current), cmd, nr);
+       if (kdata != stack_kdata)
+               kfree(kdata);
+       if (retcode)
+               dev_dbg(kfd_device, "ret = %d\n", retcode);
+       return retcode;
  }
  
  static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
index a770ec6f22cad24a878d96426ebb2f9395cefdea,633532a2e7ec875b968343975c2d49d69d220abc..1ba8332419faee78ce45f7179b379bd5a285ffb1
  #include <linux/slab.h>
  #include "kfd_priv.h"
  #include "kfd_device_queue_manager.h"
 +#include "kfd_pm4_headers.h"
  
  #define MQD_SIZE_ALIGNED 768
  
  static const struct kfd_device_info kaveri_device_info = {
 +      .asic_family = CHIP_KAVERI,
        .max_pasid_bits = 16,
        .ih_ring_entry_size = 4 * sizeof(uint32_t),
        .mqd_size_aligned = MQD_SIZE_ALIGNED
  };
  
 +static const struct kfd_device_info carrizo_device_info = {
 +      .asic_family = CHIP_CARRIZO,
 +      .max_pasid_bits = 16,
 +      .ih_ring_entry_size = 4 * sizeof(uint32_t),
 +      .num_of_watch_points = 4,
 +      .mqd_size_aligned = MQD_SIZE_ALIGNED
 +};
 +
  struct kfd_deviceid {
        unsigned short did;
        const struct kfd_device_info *device_info;
@@@ -73,13 -63,9 +73,13 @@@ static const struct kfd_deviceid suppor
        { 0x1318, &kaveri_device_info },        /* Kaveri */
        { 0x131B, &kaveri_device_info },        /* Kaveri */
        { 0x131C, &kaveri_device_info },        /* Kaveri */
 -      { 0x131D, &kaveri_device_info },        /* Kaveri */
 +      { 0x131D, &kaveri_device_info }         /* Kaveri */
  };
  
 +static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
 +                              unsigned int chunk_size);
 +static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
 +
  static const struct kfd_device_info *lookup_device_info(unsigned short did)
  {
        size_t i;
@@@ -187,39 -173,16 +187,39 @@@ bool kgd2kfd_device_init(struct kfd_de
                max_num_of_queues_per_process *
                kfd->device_info->mqd_size_aligned;
  
 -      /* add another 512KB for all other allocations on gart */
 +      /*
 +       * calculate max size of runlist packet.
 +       * There can be only 2 packets at once
 +       */
 +      size += (max_num_of_processes * sizeof(struct pm4_map_process) +
 +              max_num_of_processes * max_num_of_queues_per_process *
 +              sizeof(struct pm4_map_queues) + sizeof(struct pm4_runlist)) * 2;
 +
 +      /* Add size of HIQ & DIQ */
 +      size += KFD_KERNEL_QUEUE_SIZE * 2;
 +
 +      /* add another 512KB for all other allocations on gart (HPD, fences) */
        size += 512 * 1024;
  
 -      if (kfd2kgd->init_sa_manager(kfd->kgd, size)) {
 +      if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
 +                      &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
                dev_err(kfd_device,
 -                      "Error initializing sa manager for device (%x:%x)\n",
 -                      kfd->pdev->vendor, kfd->pdev->device);
 +                      "Could not allocate %d bytes for device (%x:%x)\n",
 +                      size, kfd->pdev->vendor, kfd->pdev->device);
                goto out;
        }
  
 +      dev_info(kfd_device,
 +              "Allocated %d bytes on gart for device(%x:%x)\n",
 +              size, kfd->pdev->vendor, kfd->pdev->device);
 +
 +      /* Initialize GTT sa with 512 byte chunk size */
 +      if (kfd_gtt_sa_init(kfd, size, 512) != 0) {
 +              dev_err(kfd_device,
 +                      "Error initializing gtt sub-allocator\n");
 +              goto kfd_gtt_sa_init_error;
 +      }
 +
        kfd_doorbell_init(kfd);
  
        if (kfd_topology_add_device(kfd) != 0) {
                goto kfd_topology_add_device_error;
        }
  
-       if (kfd_interrupt_init(kfd)) {
-               dev_err(kfd_device,
-                       "Error initializing interrupts for device (%x:%x)\n",
-                       kfd->pdev->vendor, kfd->pdev->device);
-               goto kfd_interrupt_error;
-       }
        if (!device_iommu_pasid_init(kfd)) {
                dev_err(kfd_device,
                        "Error initializing iommuv2 for device (%x:%x)\n",
                goto device_queue_manager_error;
        }
  
 -      if (kfd->dqm->start(kfd->dqm) != 0) {
 +      if (kfd->dqm->ops.start(kfd->dqm) != 0) {
                dev_err(kfd_device,
                        "Error starting queuen manager for device (%x:%x)\n",
                        kfd->pdev->vendor, kfd->pdev->device);
@@@ -274,13 -230,9 +267,11 @@@ dqm_start_error
  device_queue_manager_error:
        amd_iommu_free_device(kfd->pdev);
  device_iommu_pasid_error:
-       kfd_interrupt_exit(kfd);
- kfd_interrupt_error:
        kfd_topology_remove_device(kfd);
  kfd_topology_add_device_error:
 -      kfd2kgd->fini_sa_manager(kfd->kgd);
 +      kfd_gtt_sa_fini(kfd);
 +kfd_gtt_sa_init_error:
 +      kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        dev_err(kfd_device,
                "device (%x:%x) NOT added due to errors\n",
                kfd->pdev->vendor, kfd->pdev->device);
@@@ -293,10 -245,7 +284,9 @@@ void kgd2kfd_device_exit(struct kfd_de
        if (kfd->init_complete) {
                device_queue_manager_uninit(kfd->dqm);
                amd_iommu_free_device(kfd->pdev);
-               kfd_interrupt_exit(kfd);
                kfd_topology_remove_device(kfd);
 +              kfd_gtt_sa_fini(kfd);
 +              kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
        }
  
        kfree(kfd);
@@@ -307,7 -256,7 +297,7 @@@ void kgd2kfd_suspend(struct kfd_dev *kf
        BUG_ON(kfd == NULL);
  
        if (kfd->init_complete) {
 -              kfd->dqm->stop(kfd->dqm);
 +              kfd->dqm->ops.stop(kfd->dqm);
                amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
                amd_iommu_free_device(kfd->pdev);
        }
@@@ -328,7 -277,7 +318,7 @@@ int kgd2kfd_resume(struct kfd_dev *kfd
                        return -ENXIO;
                amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
                                                iommu_pasid_shutdown_callback);
 -              kfd->dqm->start(kfd->dqm);
 +              kfd->dqm->ops.start(kfd->dqm);
        }
  
        return 0;
  /* This is called directly from KGD at ISR. */
  void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
  {
-       if (kfd->init_complete) {
-               spin_lock(&kfd->interrupt_lock);
-               if (kfd->interrupts_active
-                   && enqueue_ih_ring_entry(kfd, ih_ring_entry))
-                       schedule_work(&kfd->interrupt_work);
-               spin_unlock(&kfd->interrupt_lock);
-       }
+       /* Process interrupts / schedule work as necessary */
  }
 +
 +static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
 +                              unsigned int chunk_size)
 +{
 +      unsigned int num_of_bits;
 +
 +      BUG_ON(!kfd);
 +      BUG_ON(!kfd->gtt_mem);
 +      BUG_ON(buf_size < chunk_size);
 +      BUG_ON(buf_size == 0);
 +      BUG_ON(chunk_size == 0);
 +
 +      kfd->gtt_sa_chunk_size = chunk_size;
 +      kfd->gtt_sa_num_of_chunks = buf_size / chunk_size;
 +
 +      num_of_bits = kfd->gtt_sa_num_of_chunks / BITS_PER_BYTE;
 +      BUG_ON(num_of_bits == 0);
 +
 +      kfd->gtt_sa_bitmap = kzalloc(num_of_bits, GFP_KERNEL);
 +
 +      if (!kfd->gtt_sa_bitmap)
 +              return -ENOMEM;
 +
 +      pr_debug("kfd: gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p\n",
 +                      kfd->gtt_sa_num_of_chunks, kfd->gtt_sa_bitmap);
 +
 +      mutex_init(&kfd->gtt_sa_lock);
 +
 +      return 0;
 +
 +}
 +
 +static void kfd_gtt_sa_fini(struct kfd_dev *kfd)
 +{
 +      mutex_destroy(&kfd->gtt_sa_lock);
 +      kfree(kfd->gtt_sa_bitmap);
 +}
 +
 +static inline uint64_t kfd_gtt_sa_calc_gpu_addr(uint64_t start_addr,
 +                                              unsigned int bit_num,
 +                                              unsigned int chunk_size)
 +{
 +      return start_addr + bit_num * chunk_size;
 +}
 +
 +static inline uint32_t *kfd_gtt_sa_calc_cpu_addr(void *start_addr,
 +                                              unsigned int bit_num,
 +                                              unsigned int chunk_size)
 +{
 +      return (uint32_t *) ((uint64_t) start_addr + bit_num * chunk_size);
 +}
 +
 +int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
 +                      struct kfd_mem_obj **mem_obj)
 +{
 +      unsigned int found, start_search, cur_size;
 +
 +      BUG_ON(!kfd);
 +
 +      if (size == 0)
 +              return -EINVAL;
 +
 +      if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size)
 +              return -ENOMEM;
 +
 +      *mem_obj = kmalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
 +      if ((*mem_obj) == NULL)
 +              return -ENOMEM;
 +
 +      pr_debug("kfd: allocated mem_obj = %p for size = %d\n", *mem_obj, size);
 +
 +      start_search = 0;
 +
 +      mutex_lock(&kfd->gtt_sa_lock);
 +
 +kfd_gtt_restart_search:
 +      /* Find the first chunk that is free */
 +      found = find_next_zero_bit(kfd->gtt_sa_bitmap,
 +                                      kfd->gtt_sa_num_of_chunks,
 +                                      start_search);
 +
 +      pr_debug("kfd: found = %d\n", found);
 +
 +      /* If there wasn't any free chunk, bail out */
 +      if (found == kfd->gtt_sa_num_of_chunks)
 +              goto kfd_gtt_no_free_chunk;
 +
 +      /* Update fields of mem_obj */
 +      (*mem_obj)->range_start = found;
 +      (*mem_obj)->range_end = found;
 +      (*mem_obj)->gpu_addr = kfd_gtt_sa_calc_gpu_addr(
 +                                      kfd->gtt_start_gpu_addr,
 +                                      found,
 +                                      kfd->gtt_sa_chunk_size);
 +      (*mem_obj)->cpu_ptr = kfd_gtt_sa_calc_cpu_addr(
 +                                      kfd->gtt_start_cpu_ptr,
 +                                      found,
 +                                      kfd->gtt_sa_chunk_size);
 +
 +      pr_debug("kfd: gpu_addr = %p, cpu_addr = %p\n",
 +                      (uint64_t *) (*mem_obj)->gpu_addr, (*mem_obj)->cpu_ptr);
 +
 +      /* If we need only one chunk, mark it as allocated and get out */
 +      if (size <= kfd->gtt_sa_chunk_size) {
 +              pr_debug("kfd: single bit\n");
 +              set_bit(found, kfd->gtt_sa_bitmap);
 +              goto kfd_gtt_out;
 +      }
 +
 +      /* Otherwise, try to see if we have enough contiguous chunks */
 +      cur_size = size - kfd->gtt_sa_chunk_size;
 +      do {
 +              (*mem_obj)->range_end =
 +                      find_next_zero_bit(kfd->gtt_sa_bitmap,
 +                                      kfd->gtt_sa_num_of_chunks, ++found);
 +              /*
 +               * If next free chunk is not contiguous than we need to
 +               * restart our search from the last free chunk we found (which
 +               * wasn't contiguous to the previous ones
 +               */
 +              if ((*mem_obj)->range_end != found) {
 +                      start_search = found;
 +                      goto kfd_gtt_restart_search;
 +              }
 +
 +              /*
 +               * If we reached end of buffer, bail out with error
 +               */
 +              if (found == kfd->gtt_sa_num_of_chunks)
 +                      goto kfd_gtt_no_free_chunk;
 +
 +              /* Check if we don't need another chunk */
 +              if (cur_size <= kfd->gtt_sa_chunk_size)
 +                      cur_size = 0;
 +              else
 +                      cur_size -= kfd->gtt_sa_chunk_size;
 +
 +      } while (cur_size > 0);
 +
 +      pr_debug("kfd: range_start = %d, range_end = %d\n",
 +              (*mem_obj)->range_start, (*mem_obj)->range_end);
 +
 +      /* Mark the chunks as allocated */
 +      for (found = (*mem_obj)->range_start;
 +              found <= (*mem_obj)->range_end;
 +              found++)
 +              set_bit(found, kfd->gtt_sa_bitmap);
 +
 +kfd_gtt_out:
 +      mutex_unlock(&kfd->gtt_sa_lock);
 +      return 0;
 +
 +kfd_gtt_no_free_chunk:
 +      pr_debug("kfd: allocation failed with mem_obj = %p\n", mem_obj);
 +      mutex_unlock(&kfd->gtt_sa_lock);
 +      kfree(mem_obj);
 +      return -ENOMEM;
 +}
 +
 +int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj)
 +{
 +      unsigned int bit;
 +
 +      BUG_ON(!kfd);
 +
 +      /* Act like kfree when trying to free a NULL object */
 +      if (!mem_obj)
 +              return 0;
 +
 +      pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n",
 +                      mem_obj, mem_obj->range_start, mem_obj->range_end);
 +
 +      mutex_lock(&kfd->gtt_sa_lock);
 +
 +      /* Mark the chunks as free */
 +      for (bit = mem_obj->range_start;
 +              bit <= mem_obj->range_end;
 +              bit++)
 +              clear_bit(bit, kfd->gtt_sa_bitmap);
 +
 +      mutex_unlock(&kfd->gtt_sa_lock);
 +
 +      kfree(mem_obj);
 +      return 0;
 +}
index e804e871ff82965bddf5a2a3fbbb62e1ac00b8ff,30c8fda9622e507f0fabc0b2386d2240b812360c..a5c69e96ba6f09c1b48824b317563a33d39ec53d
  #include <linux/types.h>
  #include <linux/printk.h>
  #include <linux/bitops.h>
 +#include <linux/sched.h>
  #include "kfd_priv.h"
  #include "kfd_device_queue_manager.h"
  #include "kfd_mqd_manager.h"
  #include "cik_regs.h"
  #include "kfd_kernel_queue.h"
 -#include "../../radeon/cik_reg.h"
  
  /* Size of the per-pipe EOP queue */
  #define CIK_HPD_EOP_BYTES_LOG2 11
  #define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
  
 -static bool is_mem_initialized;
 -
 -static int init_memory(struct device_queue_manager *dqm);
  static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
                                        unsigned int pasid, unsigned int vmid);
  
  static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
                                        struct queue *q,
                                        struct qcm_process_device *qpd);
 +
  static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock);
  static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock);
  
 +static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
 +                                      struct queue *q,
 +                                      struct qcm_process_device *qpd);
 +
 +static void deallocate_sdma_queue(struct device_queue_manager *dqm,
 +                              unsigned int sdma_queue_id);
 +
 +static inline
 +enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
 +{
 +      if (type == KFD_QUEUE_TYPE_SDMA)
 +              return KFD_MQD_TYPE_SDMA;
 +      return KFD_MQD_TYPE_CP;
 +}
  
 -static inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
 +inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
  {
        BUG_ON(!dqm || !dqm->dev);
        return dqm->dev->shared_resources.compute_pipe_count;
@@@ -79,7 -67,7 +79,7 @@@ static inline unsigned int get_pipes_nu
        return PIPE_PER_ME_CP_SCHEDULING;
  }
  
 -static inline unsigned int
 +inline unsigned int
  get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
  {
        uint32_t nybble;
        nybble = (pdd->lds_base >> 60) & 0x0E;
  
        return nybble;
 -
  }
  
 -static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
 +inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
  {
        unsigned int shared_base;
  
        return shared_base;
  }
  
 -static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble);
 -static void init_process_memory(struct device_queue_manager *dqm,
 -                              struct qcm_process_device *qpd)
 -{
 -      struct kfd_process_device *pdd;
 -      unsigned int temp;
 -
 -      BUG_ON(!dqm || !qpd);
 -
 -      pdd = qpd_to_pdd(qpd);
 -
 -      /* check if sh_mem_config register already configured */
 -      if (qpd->sh_mem_config == 0) {
 -              qpd->sh_mem_config =
 -                      ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
 -                      DEFAULT_MTYPE(MTYPE_NONCACHED) |
 -                      APE1_MTYPE(MTYPE_NONCACHED);
 -              qpd->sh_mem_ape1_limit = 0;
 -              qpd->sh_mem_ape1_base = 0;
 -      }
 -
 -      if (qpd->pqm->process->is_32bit_user_mode) {
 -              temp = get_sh_mem_bases_32(pdd);
 -              qpd->sh_mem_bases = SHARED_BASE(temp);
 -              qpd->sh_mem_config |= PTR32;
 -      } else {
 -              temp = get_sh_mem_bases_nybble_64(pdd);
 -              qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
 -      }
 -
 -      pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
 -              qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
 -}
 -
 -static void program_sh_mem_settings(struct device_queue_manager *dqm,
 +void program_sh_mem_settings(struct device_queue_manager *dqm,
                                        struct qcm_process_device *qpd)
  {
        return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
@@@ -138,6 -161,9 +138,9 @@@ static void deallocate_vmid(struct devi
  {
        int bit = qpd->vmid - KFD_VMID_START_OFFSET;
  
+       /* Release the vmid mapping */
+       set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
        set_bit(bit, (unsigned long *)&dqm->vmid_bitmap);
        qpd->vmid = 0;
        q->properties.vmid = 0;
@@@ -167,10 -193,7 +170,10 @@@ static int create_queue_nocpsch(struct 
        *allocated_vmid = qpd->vmid;
        q->properties.vmid = qpd->vmid;
  
 -      retval = create_compute_queue_nocpsch(dqm, q, qpd);
 +      if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
 +              retval = create_compute_queue_nocpsch(dqm, q, qpd);
 +      if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
 +              retval = create_sdma_queue_nocpsch(dqm, q, qpd);
  
        if (retval != 0) {
                if (list_empty(&qpd->queues_list)) {
  
        list_add(&q->list, &qpd->queues_list);
        dqm->queue_count++;
 -
 +      if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
 +              dqm->sdma_queue_count++;
        mutex_unlock(&dqm->lock);
        return 0;
  }
  static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
  {
        bool set;
 -      int pipe, bit;
 +      int pipe, bit, i;
  
        set = false;
  
 -      for (pipe = dqm->next_pipe_to_allocate; pipe < get_pipes_num(dqm);
 -                      pipe = (pipe + 1) % get_pipes_num(dqm)) {
 +      for (pipe = dqm->next_pipe_to_allocate, i = 0; i < get_pipes_num(dqm);
 +                      pipe = ((pipe + 1) % get_pipes_num(dqm)), ++i) {
                if (dqm->allocated_queues[pipe] != 0) {
                        bit = find_first_bit(
                                (unsigned long *)&dqm->allocated_queues[pipe],
@@@ -238,7 -260,7 +241,7 @@@ static int create_compute_queue_nocpsch
  
        BUG_ON(!dqm || !q || !qpd);
  
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
 +      mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
        if (mqd == NULL)
                return -ENOMEM;
  
                return retval;
        }
  
+       pr_debug("kfd: loading mqd to hqd on pipe (%d) queue (%d)\n",
+                       q->pipe,
+                       q->queue);
+       retval = mqd->load_mqd(mqd, q->mqd, q->pipe,
+                       q->queue, (uint32_t __user *) q->properties.write_ptr);
+       if (retval != 0) {
+               deallocate_hqd(dqm, q);
+               mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+               return retval;
+       }
        return 0;
  }
  
@@@ -270,32 -304,22 +285,32 @@@ static int destroy_queue_nocpsch(struc
        pr_debug("kfd: In Func %s\n", __func__);
  
        mutex_lock(&dqm->lock);
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
 -      if (mqd == NULL) {
 -              retval = -ENOMEM;
 -              goto out;
 +
 +      if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
 +              mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
 +              if (mqd == NULL) {
 +                      retval = -ENOMEM;
 +                      goto out;
 +              }
 +              deallocate_hqd(dqm, q);
 +      } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
 +              mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
 +              if (mqd == NULL) {
 +                      retval = -ENOMEM;
 +                      goto out;
 +              }
 +              dqm->sdma_queue_count--;
 +              deallocate_sdma_queue(dqm, q->sdma_id);
        }
  
        retval = mqd->destroy_mqd(mqd, q->mqd,
 -                              KFD_PREEMPT_TYPE_WAVEFRONT,
 +                              KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
                                QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
                                q->pipe, q->queue);
  
        if (retval != 0)
                goto out;
  
 -      deallocate_hqd(dqm, q);
 -
        mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
  
        list_del(&q->list);
@@@ -311,20 -335,29 +326,29 @@@ static int update_queue(struct device_q
  {
        int retval;
        struct mqd_manager *mqd;
+       bool prev_active = false;
  
        BUG_ON(!dqm || !q || !q->mqd);
  
        mutex_lock(&dqm->lock);
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
 +      mqd = dqm->ops.get_mqd_manager(dqm, q->properties.type);
        if (mqd == NULL) {
                mutex_unlock(&dqm->lock);
                return -ENOMEM;
        }
  
-       retval = mqd->update_mqd(mqd, q->mqd, &q->properties);
        if (q->properties.is_active == true)
+               prev_active = true;
+       /*
+        *
+        * check active state vs. the previous state
+        * and modify counter accordingly
+        */
+       retval = mqd->update_mqd(mqd, q->mqd, &q->properties);
+       if ((q->properties.is_active == true) && (prev_active == false))
                dqm->queue_count++;
-       else
+       else if ((q->properties.is_active == false) && (prev_active == true))
                dqm->queue_count--;
  
        if (sched_policy != KFD_SCHED_POLICY_NO_HWS)
@@@ -358,7 -391,6 +382,7 @@@ static int register_process_nocpsch(str
                                        struct qcm_process_device *qpd)
  {
        struct device_process_node *n;
 +      int retval;
  
        BUG_ON(!dqm || !qpd);
  
        mutex_lock(&dqm->lock);
        list_add(&n->list, &dqm->queues);
  
 -      init_process_memory(dqm, qpd);
 +      retval = dqm->ops_asic_specific.register_process(dqm, qpd);
 +
        dqm->processes_count++;
  
        mutex_unlock(&dqm->lock);
  
 -      return 0;
 +      return retval;
  }
  
  static int unregister_process_nocpsch(struct device_queue_manager *dqm,
@@@ -424,7 -455,48 +448,7 @@@ set_pasid_vmid_mapping(struct device_qu
                                                vmid);
  }
  
 -static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
 -{
 -      /* In 64-bit mode, we can only control the top 3 bits of the LDS,
 -       * scratch and GPUVM apertures.
 -       * The hardware fills in the remaining 59 bits according to the
 -       * following pattern:
 -       * LDS:         X0000000'00000000 - X0000001'00000000 (4GB)
 -       * Scratch:     X0000001'00000000 - X0000002'00000000 (4GB)
 -       * GPUVM:       Y0010000'00000000 - Y0020000'00000000 (1TB)
 -       *
 -       * (where X/Y is the configurable nybble with the low-bit 0)
 -       *
 -       * LDS and scratch will have the same top nybble programmed in the
 -       * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
 -       * GPUVM can have a different top nybble programmed in the
 -       * top 3 bits of SH_MEM_BASES.SHARED_BASE.
 -       * We don't bother to support different top nybbles
 -       * for LDS/Scratch and GPUVM.
 -       */
 -
 -      BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
 -              top_address_nybble == 0);
 -
 -      return PRIVATE_BASE(top_address_nybble << 12) |
 -                      SHARED_BASE(top_address_nybble << 12);
 -}
 -
 -static int init_memory(struct device_queue_manager *dqm)
 -{
 -      int i, retval;
 -
 -      for (i = 8; i < 16; i++)
 -              set_pasid_vmid_mapping(dqm, 0, i);
 -
 -      retval = kfd2kgd->init_memory(dqm->dev->kgd);
 -      if (retval == 0)
 -              is_mem_initialized = true;
 -      return retval;
 -}
 -
 -
 -static int init_pipelines(struct device_queue_manager *dqm,
 +int init_pipelines(struct device_queue_manager *dqm,
                        unsigned int pipes_num, unsigned int first_pipe)
  {
        void *hpdptr;
         * because it contains no data when there are no active queues.
         */
  
 -      err = kfd2kgd->allocate_mem(dqm->dev->kgd,
 -                              CIK_HPD_EOP_BYTES * pipes_num,
 -                              PAGE_SIZE,
 -                              KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
 -                              (struct kgd_mem **) &dqm->pipeline_mem);
 +      err = kfd_gtt_sa_allocate(dqm->dev, CIK_HPD_EOP_BYTES * pipes_num,
 +                                      &dqm->pipeline_mem);
  
        if (err) {
                pr_err("kfd: error allocate vidmem num pipes: %d\n",
  
        memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num);
  
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
 +      mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
        if (mqd == NULL) {
 -              kfd2kgd->free_mem(dqm->dev->kgd,
 -                              (struct kgd_mem *) dqm->pipeline_mem);
 +              kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
                return -ENOMEM;
        }
  
        return 0;
  }
  
 -
  static int init_scheduler(struct device_queue_manager *dqm)
  {
        int retval;
        pr_debug("kfd: In %s\n", __func__);
  
        retval = init_pipelines(dqm, get_pipes_num(dqm), KFD_DQM_FIRST_PIPE);
 -      if (retval != 0)
 -              return retval;
 -
 -      retval = init_memory(dqm);
  
        return retval;
  }
@@@ -500,7 -581,6 +524,7 @@@ static int initialize_nocpsch(struct de
        mutex_init(&dqm->lock);
        INIT_LIST_HEAD(&dqm->queues);
        dqm->queue_count = dqm->next_pipe_to_allocate = 0;
 +      dqm->sdma_queue_count = 0;
        dqm->allocated_queues = kcalloc(get_pipes_num(dqm),
                                        sizeof(unsigned int), GFP_KERNEL);
        if (!dqm->allocated_queues) {
                dqm->allocated_queues[i] = (1 << QUEUES_PER_PIPE) - 1;
  
        dqm->vmid_bitmap = (1 << VMID_PER_DEVICE) - 1;
 +      dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1;
  
        init_scheduler(dqm);
        return 0;
@@@ -530,7 -609,8 +554,7 @@@ static void uninitialize_nocpsch(struc
        for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
                kfree(dqm->mqds[i]);
        mutex_destroy(&dqm->lock);
 -      kfd2kgd->free_mem(dqm->dev->kgd,
 -                      (struct kgd_mem *) dqm->pipeline_mem);
 +      kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
  }
  
  static int start_nocpsch(struct device_queue_manager *dqm)
@@@ -543,77 -623,6 +567,77 @@@ static int stop_nocpsch(struct device_q
        return 0;
  }
  
 +static int allocate_sdma_queue(struct device_queue_manager *dqm,
 +                              unsigned int *sdma_queue_id)
 +{
 +      int bit;
 +
 +      if (dqm->sdma_bitmap == 0)
 +              return -ENOMEM;
 +
 +      bit = find_first_bit((unsigned long *)&dqm->sdma_bitmap,
 +                              CIK_SDMA_QUEUES);
 +
 +      clear_bit(bit, (unsigned long *)&dqm->sdma_bitmap);
 +      *sdma_queue_id = bit;
 +
 +      return 0;
 +}
 +
 +static void deallocate_sdma_queue(struct device_queue_manager *dqm,
 +                              unsigned int sdma_queue_id)
 +{
 +      if (sdma_queue_id < 0 || sdma_queue_id >= CIK_SDMA_QUEUES)
 +              return;
 +      set_bit(sdma_queue_id, (unsigned long *)&dqm->sdma_bitmap);
 +}
 +
 +static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q,
 +                              struct qcm_process_device *qpd)
 +{
 +      uint32_t value = SDMA_ATC;
 +
 +      if (q->process->is_32bit_user_mode)
 +              value |= SDMA_VA_PTR32 | get_sh_mem_bases_32(qpd_to_pdd(qpd));
 +      else
 +              value |= SDMA_VA_SHARED_BASE(get_sh_mem_bases_nybble_64(
 +                                                      qpd_to_pdd(qpd)));
 +      q->properties.sdma_vm_addr = value;
 +}
 +
 +static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
 +                                      struct queue *q,
 +                                      struct qcm_process_device *qpd)
 +{
 +      struct mqd_manager *mqd;
 +      int retval;
 +
 +      mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
 +      if (!mqd)
 +              return -ENOMEM;
 +
 +      retval = allocate_sdma_queue(dqm, &q->sdma_id);
 +      if (retval != 0)
 +              return retval;
 +
 +      q->properties.sdma_queue_id = q->sdma_id % CIK_SDMA_QUEUES_PER_ENGINE;
 +      q->properties.sdma_engine_id = q->sdma_id / CIK_SDMA_ENGINE_NUM;
 +
 +      pr_debug("kfd: sdma id is:    %d\n", q->sdma_id);
 +      pr_debug("     sdma queue id: %d\n", q->properties.sdma_queue_id);
 +      pr_debug("     sdma engine id: %d\n", q->properties.sdma_engine_id);
 +
 +      retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
 +                              &q->gart_mqd_addr, &q->properties);
 +      if (retval != 0) {
 +              deallocate_sdma_queue(dqm, q->sdma_id);
 +              return retval;
 +      }
 +
 +      init_sdma_vm(dqm, q, qpd);
 +      return 0;
 +}
 +
  /*
   * Device Queue Manager implementation for cp scheduler
   */
@@@ -655,9 -664,8 +679,9 @@@ static int initialize_cpsch(struct devi
        mutex_init(&dqm->lock);
        INIT_LIST_HEAD(&dqm->queues);
        dqm->queue_count = dqm->processes_count = 0;
 +      dqm->sdma_queue_count = 0;
        dqm->active_runlist = false;
 -      retval = init_pipelines(dqm, get_pipes_num(dqm), 0);
 +      retval = dqm->ops_asic_specific.initialize(dqm);
        if (retval != 0)
                goto fail_init_pipelines;
  
@@@ -688,14 -696,18 +712,14 @@@ static int start_cpsch(struct device_qu
        pr_debug("kfd: allocating fence memory\n");
  
        /* allocate fence memory on the gart */
 -      retval = kfd2kgd->allocate_mem(dqm->dev->kgd,
 -                                      sizeof(*dqm->fence_addr),
 -                                      32,
 -                                      KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
 -                                      (struct kgd_mem **) &dqm->fence_mem);
 +      retval = kfd_gtt_sa_allocate(dqm->dev, sizeof(*dqm->fence_addr),
 +                                      &dqm->fence_mem);
  
        if (retval != 0)
                goto fail_allocate_vidmem;
  
        dqm->fence_addr = dqm->fence_mem->cpu_ptr;
        dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
 -
        list_for_each_entry(node, &dqm->queues, list)
                if (node->qpd->pqm->process && dqm->dev)
                        kfd_bind_process_to_device(dqm->dev,
@@@ -724,7 -736,8 +748,7 @@@ static int stop_cpsch(struct device_que
                pdd = qpd_to_pdd(node->qpd);
                pdd->bound = false;
        }
 -      kfd2kgd->free_mem(dqm->dev->kgd,
 -                      (struct kgd_mem *) dqm->fence_mem);
 +      kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
        pm_uninit(&dqm->packets);
  
        return 0;
@@@ -765,14 -778,6 +789,14 @@@ static void destroy_kernel_queue_cpsch(
        mutex_unlock(&dqm->lock);
  }
  
 +static void select_sdma_engine_id(struct queue *q)
 +{
 +      static int sdma_id;
 +
 +      q->sdma_id = sdma_id;
 +      sdma_id = (sdma_id + 1) % 2;
 +}
 +
  static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
                        struct qcm_process_device *qpd, int *allocate_vmid)
  {
  
        mutex_lock(&dqm->lock);
  
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
 +      if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
 +              select_sdma_engine_id(q);
 +
 +      mqd = dqm->ops.get_mqd_manager(dqm,
 +                      get_mqd_type_from_queue_type(q->properties.type));
 +
        if (mqd == NULL) {
                mutex_unlock(&dqm->lock);
                return -ENOMEM;
                retval = execute_queues_cpsch(dqm, false);
        }
  
 +      if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
 +                      dqm->sdma_queue_count++;
 +
  out:
        mutex_unlock(&dqm->lock);
        return retval;
@@@ -830,20 -827,12 +854,20 @@@ static int fence_wait_timeout(unsigned 
                        pr_err("kfd: qcm fence wait loop timeout expired\n");
                        return -ETIME;
                }
 -              cpu_relax();
 +              schedule();
        }
  
        return 0;
  }
  
 +static int destroy_sdma_queues(struct device_queue_manager *dqm,
 +                              unsigned int sdma_engine)
 +{
 +      return pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_SDMA,
 +                      KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false,
 +                      sdma_engine);
 +}
 +
  static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
  {
        int retval;
                mutex_lock(&dqm->lock);
        if (dqm->active_runlist == false)
                goto out;
 +
 +      pr_debug("kfd: Before destroying queues, sdma queue count is : %u\n",
 +              dqm->sdma_queue_count);
 +
 +      if (dqm->sdma_queue_count > 0) {
 +              destroy_sdma_queues(dqm, 0);
 +              destroy_sdma_queues(dqm, 1);
 +      }
 +
        retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_COMPUTE,
                        KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false, 0);
        if (retval != 0)
@@@ -936,16 -916,13 +960,16 @@@ static int destroy_queue_cpsch(struct d
  
        /* remove queue from list to prevent rescheduling after preemption */
        mutex_lock(&dqm->lock);
 -
 -      mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
 +      mqd = dqm->ops.get_mqd_manager(dqm,
 +                      get_mqd_type_from_queue_type(q->properties.type));
        if (!mqd) {
                retval = -ENOMEM;
                goto failed;
        }
  
 +      if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
 +              dqm->sdma_queue_count--;
 +
        list_del(&q->list);
        dqm->queue_count--;
  
@@@ -977,7 -954,8 +1001,7 @@@ static bool set_cache_memory_policy(str
                                   void __user *alternate_aperture_base,
                                   uint64_t alternate_aperture_size)
  {
 -      uint32_t default_mtype;
 -      uint32_t ape1_mtype;
 +      bool retval;
  
        pr_debug("kfd: In func %s\n", __func__);
  
                qpd->sh_mem_ape1_limit = limit >> 16;
        }
  
 -      default_mtype = (default_policy == cache_policy_coherent) ?
 -                      MTYPE_NONCACHED :
 -                      MTYPE_CACHED;
 -
 -      ape1_mtype = (alternate_policy == cache_policy_coherent) ?
 -                      MTYPE_NONCACHED :
 -                      MTYPE_CACHED;
 -
 -      qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
 -                      | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
 -                      | DEFAULT_MTYPE(default_mtype)
 -                      | APE1_MTYPE(ape1_mtype);
 +      retval = dqm->ops_asic_specific.set_cache_memory_policy(
 +                      dqm,
 +                      qpd,
 +                      default_policy,
 +                      alternate_policy,
 +                      alternate_aperture_base,
 +                      alternate_aperture_size);
  
        if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
                program_sh_mem_settings(dqm, qpd);
                qpd->sh_mem_ape1_limit);
  
        mutex_unlock(&dqm->lock);
 -      return true;
 +      return retval;
  
  out:
        mutex_unlock(&dqm->lock);
@@@ -1043,8 -1026,6 +1067,8 @@@ struct device_queue_manager *device_que
  
        BUG_ON(!dev);
  
 +      pr_debug("kfd: loading device queue manager\n");
 +
        dqm = kzalloc(sizeof(struct device_queue_manager), GFP_KERNEL);
        if (!dqm)
                return NULL;
        case KFD_SCHED_POLICY_HWS:
        case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
                /* initialize dqm for cp scheduling */
 -              dqm->create_queue = create_queue_cpsch;
 -              dqm->initialize = initialize_cpsch;
 -              dqm->start = start_cpsch;
 -              dqm->stop = stop_cpsch;
 -              dqm->destroy_queue = destroy_queue_cpsch;
 -              dqm->update_queue = update_queue;
 -              dqm->get_mqd_manager = get_mqd_manager_nocpsch;
 -              dqm->register_process = register_process_nocpsch;
 -              dqm->unregister_process = unregister_process_nocpsch;
 -              dqm->uninitialize = uninitialize_nocpsch;
 -              dqm->create_kernel_queue = create_kernel_queue_cpsch;
 -              dqm->destroy_kernel_queue = destroy_kernel_queue_cpsch;
 -              dqm->set_cache_memory_policy = set_cache_memory_policy;
 +              dqm->ops.create_queue = create_queue_cpsch;
 +              dqm->ops.initialize = initialize_cpsch;
 +              dqm->ops.start = start_cpsch;
 +              dqm->ops.stop = stop_cpsch;
 +              dqm->ops.destroy_queue = destroy_queue_cpsch;
 +              dqm->ops.update_queue = update_queue;
 +              dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
 +              dqm->ops.register_process = register_process_nocpsch;
 +              dqm->ops.unregister_process = unregister_process_nocpsch;
 +              dqm->ops.uninitialize = uninitialize_nocpsch;
 +              dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
 +              dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
 +              dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
                break;
        case KFD_SCHED_POLICY_NO_HWS:
                /* initialize dqm for no cp scheduling */
 -              dqm->start = start_nocpsch;
 -              dqm->stop = stop_nocpsch;
 -              dqm->create_queue = create_queue_nocpsch;
 -              dqm->destroy_queue = destroy_queue_nocpsch;
 -              dqm->update_queue = update_queue;
 -              dqm->get_mqd_manager = get_mqd_manager_nocpsch;
 -              dqm->register_process = register_process_nocpsch;
 -              dqm->unregister_process = unregister_process_nocpsch;
 -              dqm->initialize = initialize_nocpsch;
 -              dqm->uninitialize = uninitialize_nocpsch;
 -              dqm->set_cache_memory_policy = set_cache_memory_policy;
 +              dqm->ops.start = start_nocpsch;
 +              dqm->ops.stop = stop_nocpsch;
 +              dqm->ops.create_queue = create_queue_nocpsch;
 +              dqm->ops.destroy_queue = destroy_queue_nocpsch;
 +              dqm->ops.update_queue = update_queue;
 +              dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
 +              dqm->ops.register_process = register_process_nocpsch;
 +              dqm->ops.unregister_process = unregister_process_nocpsch;
 +              dqm->ops.initialize = initialize_nocpsch;
 +              dqm->ops.uninitialize = uninitialize_nocpsch;
 +              dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
                break;
        default:
                BUG();
                break;
        }
  
 -      if (dqm->initialize(dqm) != 0) {
 +      switch (dev->device_info->asic_family) {
 +      case CHIP_CARRIZO:
 +              device_queue_manager_init_vi(&dqm->ops_asic_specific);
 +      case CHIP_KAVERI:
 +              device_queue_manager_init_cik(&dqm->ops_asic_specific);
 +      }
 +
 +      if (dqm->ops.initialize(dqm) != 0) {
                kfree(dqm);
                return NULL;
        }
@@@ -1106,6 -1080,7 +1130,6 @@@ void device_queue_manager_uninit(struc
  {
        BUG_ON(!dqm);
  
 -      dqm->uninitialize(dqm);
 +      dqm->ops.uninitialize(dqm);
        kfree(dqm);
  }
 -
index 4e582debfaa91d385bc0311f059fa1891bb15061,0000000000000000000000000000000000000000..a318743cdcc2cce1a4b915c962fadb92d13445f0
mode 100644,000000..100644
--- /dev/null
@@@ -1,448 -1,0 +1,448 @@@
-       return kfd2kgd->hqd_is_occupies(mm->dev->kgd, queue_address,
 +/*
 + * Copyright 2014 Advanced Micro Devices, Inc.
 + *
 + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 <linux/printk.h>
 +#include <linux/slab.h>
 +#include "kfd_priv.h"
 +#include "kfd_mqd_manager.h"
 +#include "cik_regs.h"
 +#include "cik_structs.h"
 +
 +static inline struct cik_mqd *get_mqd(void *mqd)
 +{
 +      return (struct cik_mqd *)mqd;
 +}
 +
 +static int init_mqd(struct mqd_manager *mm, void **mqd,
 +              struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
 +              struct queue_properties *q)
 +{
 +      uint64_t addr;
 +      struct cik_mqd *m;
 +      int retval;
 +
 +      BUG_ON(!mm || !q || !mqd);
 +
 +      pr_debug("kfd: In func %s\n", __func__);
 +
 +      retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
 +                                      mqd_mem_obj);
 +
 +      if (retval != 0)
 +              return -ENOMEM;
 +
 +      m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
 +      addr = (*mqd_mem_obj)->gpu_addr;
 +
 +      memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
 +
 +      m->header = 0xC0310800;
 +      m->compute_pipelinestat_enable = 1;
 +      m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
 +
 +      /*
 +       * Make sure to use the last queue state saved on mqd when the cp
 +       * reassigns the queue, so when queue is switched on/off (e.g over
 +       * subscription or quantum timeout) the context will be consistent
 +       */
 +      m->cp_hqd_persistent_state =
 +                              DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
 +
 +      m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
 +      m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
 +      m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
 +
 +      m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
 +      /* Although WinKFD writes this, I suspect it should not be necessary */
 +      m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
 +
 +      m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
 +                              QUANTUM_DURATION(10);
 +
 +      /*
 +       * Pipe Priority
 +       * Identifies the pipe relative priority when this queue is connected
 +       * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
 +       * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
 +       * 0 = CS_LOW (typically below GFX)
 +       * 1 = CS_MEDIUM (typically between HP3D and GFX
 +       * 2 = CS_HIGH (typically above HP3D)
 +       */
 +      m->cp_hqd_pipe_priority = 1;
 +      m->cp_hqd_queue_priority = 15;
 +
 +      *mqd = m;
 +      if (gart_addr != NULL)
 +              *gart_addr = addr;
 +      retval = mm->update_mqd(mm, m, q);
 +
 +      return retval;
 +}
 +
 +static int init_mqd_sdma(struct mqd_manager *mm, void **mqd,
 +                      struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
 +                      struct queue_properties *q)
 +{
 +      int retval;
 +      struct cik_sdma_rlc_registers *m;
 +
 +      BUG_ON(!mm || !mqd || !mqd_mem_obj);
 +
 +      retval = kfd_gtt_sa_allocate(mm->dev,
 +                                      sizeof(struct cik_sdma_rlc_registers),
 +                                      mqd_mem_obj);
 +
 +      if (retval != 0)
 +              return -ENOMEM;
 +
 +      m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr;
 +
 +      memset(m, 0, sizeof(struct cik_sdma_rlc_registers));
 +
 +      *mqd = m;
 +      if (gart_addr != NULL)
 +              *gart_addr = (*mqd_mem_obj)->gpu_addr;
 +
 +      retval = mm->update_mqd(mm, m, q);
 +
 +      return retval;
 +}
 +
 +static void uninit_mqd(struct mqd_manager *mm, void *mqd,
 +                      struct kfd_mem_obj *mqd_mem_obj)
 +{
 +      BUG_ON(!mm || !mqd);
 +      kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
 +}
 +
 +static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
 +                              struct kfd_mem_obj *mqd_mem_obj)
 +{
 +      BUG_ON(!mm || !mqd);
 +      kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
 +}
 +
 +static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
 +                      uint32_t queue_id, uint32_t __user *wptr)
 +{
 +      return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
 +}
 +
 +static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
 +                      uint32_t pipe_id, uint32_t queue_id,
 +                      uint32_t __user *wptr)
 +{
 +      return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
 +}
 +
 +static int update_mqd(struct mqd_manager *mm, void *mqd,
 +                      struct queue_properties *q)
 +{
 +      struct cik_mqd *m;
 +
 +      BUG_ON(!mm || !q || !mqd);
 +
 +      pr_debug("kfd: In func %s\n", __func__);
 +
 +      m = get_mqd(mqd);
 +      m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
 +                              DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
 +
 +      /*
 +       * Calculating queue size which is log base 2 of actual queue size -1
 +       * dwords and another -1 for ffs
 +       */
 +      m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
 +                                                              - 1 - 1;
 +      m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
 +      m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
 +      m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
 +      m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
 +      m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
 +                                      DOORBELL_OFFSET(q->doorbell_off);
 +
 +      m->cp_hqd_vmid = q->vmid;
 +
 +      if (q->format == KFD_QUEUE_FORMAT_AQL) {
 +              m->cp_hqd_iq_rptr = AQL_ENABLE;
 +              m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
 +      }
 +
 +      m->cp_hqd_active = 0;
 +      q->is_active = false;
 +      if (q->queue_size > 0 &&
 +                      q->queue_address != 0 &&
 +                      q->queue_percent > 0) {
 +              m->cp_hqd_active = 1;
 +              q->is_active = true;
 +      }
 +
 +      return 0;
 +}
 +
 +static int update_mqd_sdma(struct mqd_manager *mm, void *mqd,
 +                              struct queue_properties *q)
 +{
 +      struct cik_sdma_rlc_registers *m;
 +
 +      BUG_ON(!mm || !mqd || !q);
 +
 +      m = get_sdma_mqd(mqd);
 +      m->sdma_rlc_rb_cntl =
 +              SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) |
 +              SDMA_RB_VMID(q->vmid) |
 +              SDMA_RPTR_WRITEBACK_ENABLE |
 +              SDMA_RPTR_WRITEBACK_TIMER(6);
 +
 +      m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8);
 +      m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8);
 +      m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
 +      m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
 +      m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE;
 +      m->sdma_rlc_virtual_addr = q->sdma_vm_addr;
 +
 +      m->sdma_engine_id = q->sdma_engine_id;
 +      m->sdma_queue_id = q->sdma_queue_id;
 +
 +      q->is_active = false;
 +      if (q->queue_size > 0 &&
 +                      q->queue_address != 0 &&
 +                      q->queue_percent > 0) {
 +              m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE;
 +              q->is_active = true;
 +      }
 +
 +      return 0;
 +}
 +
 +static int destroy_mqd(struct mqd_manager *mm, void *mqd,
 +                      enum kfd_preempt_type type,
 +                      unsigned int timeout, uint32_t pipe_id,
 +                      uint32_t queue_id)
 +{
 +      return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
 +                                      pipe_id, queue_id);
 +}
 +
 +/*
 + * preempt type here is ignored because there is only one way
 + * to preempt sdma queue
 + */
 +static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
 +                              enum kfd_preempt_type type,
 +                              unsigned int timeout, uint32_t pipe_id,
 +                              uint32_t queue_id)
 +{
 +      return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
 +}
 +
 +static bool is_occupied(struct mqd_manager *mm, void *mqd,
 +                      uint64_t queue_address, uint32_t pipe_id,
 +                      uint32_t queue_id)
 +{
 +
++      return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
 +                                      pipe_id, queue_id);
 +
 +}
 +
 +static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
 +                      uint64_t queue_address, uint32_t pipe_id,
 +                      uint32_t queue_id)
 +{
 +      return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
 +}
 +
 +/*
 + * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
 + * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
 + * queues but with different initial values.
 + */
 +
 +static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
 +              struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
 +              struct queue_properties *q)
 +{
 +      uint64_t addr;
 +      struct cik_mqd *m;
 +      int retval;
 +
 +      BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
 +
 +      pr_debug("kfd: In func %s\n", __func__);
 +
 +      retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
 +                                      mqd_mem_obj);
 +
 +      if (retval != 0)
 +              return -ENOMEM;
 +
 +      m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
 +      addr = (*mqd_mem_obj)->gpu_addr;
 +
 +      memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
 +
 +      m->header = 0xC0310800;
 +      m->compute_pipelinestat_enable = 1;
 +      m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
 +      m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
 +
 +      m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
 +                                      PRELOAD_REQ;
 +      m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
 +                              QUANTUM_DURATION(10);
 +
 +      m->cp_mqd_control             = MQD_CONTROL_PRIV_STATE_EN;
 +      m->cp_mqd_base_addr_lo        = lower_32_bits(addr);
 +      m->cp_mqd_base_addr_hi        = upper_32_bits(addr);
 +
 +      m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
 +
 +      /*
 +       * Pipe Priority
 +       * Identifies the pipe relative priority when this queue is connected
 +       * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
 +       * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
 +       * 0 = CS_LOW (typically below GFX)
 +       * 1 = CS_MEDIUM (typically between HP3D and GFX
 +       * 2 = CS_HIGH (typically above HP3D)
 +       */
 +      m->cp_hqd_pipe_priority = 1;
 +      m->cp_hqd_queue_priority = 15;
 +
 +      *mqd = m;
 +      if (gart_addr)
 +              *gart_addr = addr;
 +      retval = mm->update_mqd(mm, m, q);
 +
 +      return retval;
 +}
 +
 +static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
 +                              struct queue_properties *q)
 +{
 +      struct cik_mqd *m;
 +
 +      BUG_ON(!mm || !q || !mqd);
 +
 +      pr_debug("kfd: In func %s\n", __func__);
 +
 +      m = get_mqd(mqd);
 +      m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
 +                              DEFAULT_MIN_AVAIL_SIZE |
 +                              PRIV_STATE |
 +                              KMD_QUEUE;
 +
 +      /*
 +       * Calculating queue size which is log base 2 of actual queue
 +       * size -1 dwords
 +       */
 +      m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
 +                                                              - 1 - 1;
 +      m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
 +      m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
 +      m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
 +      m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
 +      m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
 +                                      DOORBELL_OFFSET(q->doorbell_off);
 +
 +      m->cp_hqd_vmid = q->vmid;
 +
 +      m->cp_hqd_active = 0;
 +      q->is_active = false;
 +      if (q->queue_size > 0 &&
 +                      q->queue_address != 0 &&
 +                      q->queue_percent > 0) {
 +              m->cp_hqd_active = 1;
 +              q->is_active = true;
 +      }
 +
 +      return 0;
 +}
 +
 +struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
 +{
 +      struct cik_sdma_rlc_registers *m;
 +
 +      BUG_ON(!mqd);
 +
 +      m = (struct cik_sdma_rlc_registers *)mqd;
 +
 +      return m;
 +}
 +
 +struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
 +              struct kfd_dev *dev)
 +{
 +      struct mqd_manager *mqd;
 +
 +      BUG_ON(!dev);
 +      BUG_ON(type >= KFD_MQD_TYPE_MAX);
 +
 +      pr_debug("kfd: In func %s\n", __func__);
 +
 +      mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
 +      if (!mqd)
 +              return NULL;
 +
 +      mqd->dev = dev;
 +
 +      switch (type) {
 +      case KFD_MQD_TYPE_CP:
 +      case KFD_MQD_TYPE_COMPUTE:
 +              mqd->init_mqd = init_mqd;
 +              mqd->uninit_mqd = uninit_mqd;
 +              mqd->load_mqd = load_mqd;
 +              mqd->update_mqd = update_mqd;
 +              mqd->destroy_mqd = destroy_mqd;
 +              mqd->is_occupied = is_occupied;
 +              break;
 +      case KFD_MQD_TYPE_HIQ:
 +              mqd->init_mqd = init_mqd_hiq;
 +              mqd->uninit_mqd = uninit_mqd;
 +              mqd->load_mqd = load_mqd;
 +              mqd->update_mqd = update_mqd_hiq;
 +              mqd->destroy_mqd = destroy_mqd;
 +              mqd->is_occupied = is_occupied;
 +              break;
 +      case KFD_MQD_TYPE_SDMA:
 +              mqd->init_mqd = init_mqd_sdma;
 +              mqd->uninit_mqd = uninit_mqd_sdma;
 +              mqd->load_mqd = load_mqd_sdma;
 +              mqd->update_mqd = update_mqd_sdma;
 +              mqd->destroy_mqd = destroy_mqd_sdma;
 +              mqd->is_occupied = is_occupied_sdma;
 +              break;
 +      default:
 +              kfree(mqd);
 +              return NULL;
 +      }
 +
 +      return mqd;
 +}
 +
index bfcf45f30b76937402ade90bc98427187534ba7d,b3dc13c83169c1a3fb5cd54c9ae179aaf9508d36..1b35a9c87437d89cf761c5d2e9e992ffe7813ae3
@@@ -104,26 -104,12 +104,26 @@@ enum cache_policy 
        cache_policy_noncoherent
  };
  
 +enum asic_family_type {
 +      CHIP_KAVERI = 0,
 +      CHIP_CARRIZO
 +};
 +
  struct kfd_device_info {
 +      unsigned int asic_family;
        unsigned int max_pasid_bits;
        size_t ih_ring_entry_size;
 +      uint8_t num_of_watch_points;
        uint16_t mqd_size_aligned;
  };
  
 +struct kfd_mem_obj {
 +      uint32_t range_start;
 +      uint32_t range_end;
 +      uint64_t gpu_addr;
 +      uint32_t *cpu_ptr;
 +};
 +
  struct kfd_dev {
        struct kgd_dev *kgd;
  
  
        struct kgd2kfd_shared_resources shared_resources;
  
-       void *interrupt_ring;
-       size_t interrupt_ring_size;
-       atomic_t interrupt_ring_rptr;
-       atomic_t interrupt_ring_wptr;
-       struct work_struct interrupt_work;
-       spinlock_t interrupt_lock;
 +      void *gtt_mem;
 +      uint64_t gtt_start_gpu_addr;
 +      void *gtt_start_cpu_ptr;
 +      void *gtt_sa_bitmap;
 +      struct mutex gtt_sa_lock;
 +      unsigned int gtt_sa_chunk_size;
 +      unsigned int gtt_sa_num_of_chunks;
 +
        /* QCM Device instance */
        struct device_queue_manager *dqm;
  
        bool init_complete;
-       /*
-        * Interrupts of interest to KFD are copied
-        * from the HW ring into a SW ring.
-        */
-       bool interrupts_active;
  };
  
  /* KGD2KFD callbacks */
@@@ -184,6 -150,12 +172,6 @@@ void kgd2kfd_device_exit(struct kfd_de
  
  extern const struct kfd2kgd_calls *kfd2kgd;
  
 -struct kfd_mem_obj {
 -      void *bo;
 -      uint64_t gpu_addr;
 -      uint32_t *cpu_ptr;
 -};
 -
  enum kfd_mempool {
        KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
        KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@@ -301,15 -273,6 +289,15 @@@ struct queue_properties 
        bool is_active;
        /* Not relevant for user mode queues in cp scheduling */
        unsigned int vmid;
 +      /* Relevant only for sdma queues*/
 +      uint32_t sdma_engine_id;
 +      uint32_t sdma_queue_id;
 +      uint32_t sdma_vm_addr;
 +      /* Relevant only for VI */
 +      uint64_t eop_ring_buffer_address;
 +      uint32_t eop_ring_buffer_size;
 +      uint64_t ctx_save_restore_area_address;
 +      uint32_t ctx_save_restore_area_size;
  };
  
  /**
@@@ -352,8 -315,6 +340,8 @@@ struct queue 
        uint32_t pipe;
        uint32_t queue;
  
 +      unsigned int sdma_id;
 +
        struct kfd_process      *process;
        struct kfd_dev          *device;
  };
   * Please read the kfd_mqd_manager.h description.
   */
  enum KFD_MQD_TYPE {
 -      KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */
 -      KFD_MQD_TYPE_CIK_HIQ, /* for hiq */
 -      KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */
 -      KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */
 +      KFD_MQD_TYPE_COMPUTE = 0,       /* for no cp scheduling */
 +      KFD_MQD_TYPE_HIQ,               /* for hiq */
 +      KFD_MQD_TYPE_CP,                /* for cp queues and diq */
 +      KFD_MQD_TYPE_SDMA,              /* for sdma queues */
        KFD_MQD_TYPE_MAX
  };
  
@@@ -490,6 -451,24 +478,24 @@@ struct kfd_process 
        bool is_32bit_user_mode;
  };
  
+ /**
+  * Ioctl function type.
+  *
+  * \param filep pointer to file structure.
+  * \param p amdkfd process pointer.
+  * \param data pointer to arg that was copied from user.
+  */
+ typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p,
+                               void *data);
+ struct amdkfd_ioctl_desc {
+       unsigned int cmd;
+       int flags;
+       amdkfd_ioctl_t *func;
+       unsigned int cmd_drv;
+       const char *name;
+ };
  void kfd_process_create_wq(void);
  void kfd_process_destroy_wq(void);
  struct kfd_process *kfd_create_process(const struct task_struct *);
@@@ -499,9 -478,8 +505,9 @@@ struct kfd_process_device *kfd_bind_pro
                                                        struct kfd_process *p);
  void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid);
  struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
 -                                                      struct kfd_process *p,
 -                                                      int create_pdd);
 +                                                      struct kfd_process *p);
 +struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
 +                                                      struct kfd_process *p);
  
  /* Process device data iterator */
  struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p);
@@@ -529,13 -507,6 +535,13 @@@ unsigned int kfd_queue_id_to_doorbell(s
                                        struct kfd_process *process,
                                        unsigned int queue_id);
  
 +/* GTT Sub-Allocator */
 +
 +int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
 +                      struct kfd_mem_obj **mem_obj);
 +
 +int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj);
 +
  extern struct device *kfd_device;
  
  /* Topology */
@@@ -548,10 -519,7 +554,7 @@@ struct kfd_dev *kfd_device_by_pci_dev(c
  struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx);
  
  /* Interrupts */
- int kfd_interrupt_init(struct kfd_dev *dev);
- void kfd_interrupt_exit(struct kfd_dev *dev);
  void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
- bool enqueue_ih_ring_entry(struct kfd_dev *kfd,       const void *ih_ring_entry);
  
  /* Power Management */
  void kgd2kfd_suspend(struct kfd_dev *kfd);
@@@ -563,8 -531,6 +566,8 @@@ int kfd_init_apertures(struct kfd_proce
  /* Queue Context Management */
  inline uint32_t lower_32(uint64_t x);
  inline uint32_t upper_32(uint64_t x);
 +struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
 +inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m);
  
  int init_queue(struct queue **q, struct queue_properties properties);
  void uninit_queue(struct queue *q);
@@@ -573,10 -539,6 +576,10 @@@ void print_queue(struct queue *q)
  
  struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
                                        struct kfd_dev *dev);
 +struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
 +              struct kfd_dev *dev);
 +struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
 +              struct kfd_dev *dev);
  struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev);
  void device_queue_manager_uninit(struct device_queue_manager *dqm);
  struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
index 4886dde7d1fba5e1e927f433b398711e2b4bee7b,cca1708fd811be8253ab0d2989d74e405f3dab04..498399323a8cd503f35fb3e828abf08c2368cad8
@@@ -27,7 -27,6 +27,7 @@@
  #include <linux/acpi.h>
  #include <linux/hash.h>
  #include <linux/cpufreq.h>
 +#include <linux/log2.h>
  
  #include "kfd_priv.h"
  #include "kfd_crat.h"
@@@ -631,10 -630,10 +631,10 @@@ static struct kobj_type cache_type = 
  static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                char *buffer)
  {
 -      ssize_t ret;
        struct kfd_topology_device *dev;
        char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
        uint32_t i;
 +      uint32_t log_max_watch_addr;
  
        /* Making sure that the buffer is an empty string */
        buffer[0] = 0;
        if (strcmp(attr->name, "gpu_id") == 0) {
                dev = container_of(attr, struct kfd_topology_device,
                                attr_gpuid);
 -              ret = sysfs_show_32bit_val(buffer, dev->gpu_id);
 -      } else if (strcmp(attr->name, "name") == 0) {
 +              return sysfs_show_32bit_val(buffer, dev->gpu_id);
 +      }
 +
 +      if (strcmp(attr->name, "name") == 0) {
                dev = container_of(attr, struct kfd_topology_device,
                                attr_name);
                for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) {
                                break;
                }
                public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0;
 -              ret = sysfs_show_str_val(buffer, public_name);
 -      } else {
 -              dev = container_of(attr, struct kfd_topology_device,
 -                              attr_props);
 -              sysfs_show_32bit_prop(buffer, "cpu_cores_count",
 -                              dev->node_props.cpu_cores_count);
 -              sysfs_show_32bit_prop(buffer, "simd_count",
 -                              dev->node_props.simd_count);
 -
 -              if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
 -                      pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
 -                                      dev->node_props.mem_banks_count,
 -                                      dev->mem_bank_count);
 -                      sysfs_show_32bit_prop(buffer, "mem_banks_count",
 -                                      dev->mem_bank_count);
 -              } else {
 -                      sysfs_show_32bit_prop(buffer, "mem_banks_count",
 -                                      dev->node_props.mem_banks_count);
 -              }
 +              return sysfs_show_str_val(buffer, public_name);
 +      }
  
 -              sysfs_show_32bit_prop(buffer, "caches_count",
 -                              dev->node_props.caches_count);
 -              sysfs_show_32bit_prop(buffer, "io_links_count",
 -                              dev->node_props.io_links_count);
 -              sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
 -                              dev->node_props.cpu_core_id_base);
 -              sysfs_show_32bit_prop(buffer, "simd_id_base",
 -                              dev->node_props.simd_id_base);
 -              sysfs_show_32bit_prop(buffer, "capability",
 -                              dev->node_props.capability);
 -              sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
 -                              dev->node_props.max_waves_per_simd);
 -              sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
 -                              dev->node_props.lds_size_in_kb);
 -              sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
 -                              dev->node_props.gds_size_in_kb);
 -              sysfs_show_32bit_prop(buffer, "wave_front_size",
 -                              dev->node_props.wave_front_size);
 -              sysfs_show_32bit_prop(buffer, "array_count",
 -                              dev->node_props.array_count);
 -              sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
 -                              dev->node_props.simd_arrays_per_engine);
 -              sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
 -                              dev->node_props.cu_per_simd_array);
 -              sysfs_show_32bit_prop(buffer, "simd_per_cu",
 -                              dev->node_props.simd_per_cu);
 -              sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
 -                              dev->node_props.max_slots_scratch_cu);
 -              sysfs_show_32bit_prop(buffer, "vendor_id",
 -                              dev->node_props.vendor_id);
 -              sysfs_show_32bit_prop(buffer, "device_id",
 -                              dev->node_props.device_id);
 -              sysfs_show_32bit_prop(buffer, "location_id",
 -                              dev->node_props.location_id);
 -
 -              if (dev->gpu) {
 -                      sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
 -                                      kfd2kgd->get_max_engine_clock_in_mhz(
 -                                              dev->gpu->kgd));
 -                      sysfs_show_64bit_prop(buffer, "local_mem_size",
 -                                      kfd2kgd->get_vmem_size(dev->gpu->kgd));
 -
 -                      sysfs_show_32bit_prop(buffer, "fw_version",
 -                                      kfd2kgd->get_fw_version(
 -                                                      dev->gpu->kgd,
 -                                                      KGD_ENGINE_MEC1));
 +      dev = container_of(attr, struct kfd_topology_device,
 +                      attr_props);
 +      sysfs_show_32bit_prop(buffer, "cpu_cores_count",
 +                      dev->node_props.cpu_cores_count);
 +      sysfs_show_32bit_prop(buffer, "simd_count",
 +                      dev->node_props.simd_count);
 +
 +      if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
 +              pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
 +                              dev->node_props.mem_banks_count,
 +                              dev->mem_bank_count);
 +              sysfs_show_32bit_prop(buffer, "mem_banks_count",
 +                              dev->mem_bank_count);
 +      } else {
 +              sysfs_show_32bit_prop(buffer, "mem_banks_count",
 +                              dev->node_props.mem_banks_count);
 +      }
  
 +      sysfs_show_32bit_prop(buffer, "caches_count",
 +                      dev->node_props.caches_count);
 +      sysfs_show_32bit_prop(buffer, "io_links_count",
 +                      dev->node_props.io_links_count);
 +      sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
 +                      dev->node_props.cpu_core_id_base);
 +      sysfs_show_32bit_prop(buffer, "simd_id_base",
 +                      dev->node_props.simd_id_base);
 +      sysfs_show_32bit_prop(buffer, "capability",
 +                      dev->node_props.capability);
 +      sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
 +                      dev->node_props.max_waves_per_simd);
 +      sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
 +                      dev->node_props.lds_size_in_kb);
 +      sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
 +                      dev->node_props.gds_size_in_kb);
 +      sysfs_show_32bit_prop(buffer, "wave_front_size",
 +                      dev->node_props.wave_front_size);
 +      sysfs_show_32bit_prop(buffer, "array_count",
 +                      dev->node_props.array_count);
 +      sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
 +                      dev->node_props.simd_arrays_per_engine);
 +      sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
 +                      dev->node_props.cu_per_simd_array);
 +      sysfs_show_32bit_prop(buffer, "simd_per_cu",
 +                      dev->node_props.simd_per_cu);
 +      sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
 +                      dev->node_props.max_slots_scratch_cu);
 +      sysfs_show_32bit_prop(buffer, "vendor_id",
 +                      dev->node_props.vendor_id);
 +      sysfs_show_32bit_prop(buffer, "device_id",
 +                      dev->node_props.device_id);
 +      sysfs_show_32bit_prop(buffer, "location_id",
 +                      dev->node_props.location_id);
 +
 +      if (dev->gpu) {
 +              log_max_watch_addr =
 +                      __ilog2_u32(dev->gpu->device_info->num_of_watch_points);
 +
 +              if (log_max_watch_addr) {
 +                      dev->node_props.capability |=
 +                                      HSA_CAP_WATCH_POINTS_SUPPORTED;
 +
 +                      dev->node_props.capability |=
 +                              ((log_max_watch_addr <<
 +                                      HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) &
 +                              HSA_CAP_WATCH_POINTS_TOTALBITS_MASK);
                }
  
 -              ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
 -                              cpufreq_quick_get_max(0)/1000);
 +              sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
 +                              kfd2kgd->get_max_engine_clock_in_mhz(
 +                                      dev->gpu->kgd));
 +              sysfs_show_64bit_prop(buffer, "local_mem_size",
 +                              kfd2kgd->get_vmem_size(dev->gpu->kgd));
 +
 +              sysfs_show_32bit_prop(buffer, "fw_version",
 +                              kfd2kgd->get_fw_version(
 +                                              dev->gpu->kgd,
 +                                              KGD_ENGINE_MEC1));
        }
  
 -      return ret;
 +      return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
 +                                      cpufreq_quick_get_max(0)/1000);
  }
  
  static const struct sysfs_ops node_ops = {
@@@ -934,7 -921,7 +934,7 @@@ static int kfd_build_sysfs_node_tree(vo
        uint32_t i = 0;
  
        list_for_each_entry(dev, &topology_device_list, list) {
-               ret = kfd_build_sysfs_node_entry(dev, 0);
+               ret = kfd_build_sysfs_node_entry(dev, i);
                if (ret < 0)
                        return ret;
                i++;
index 883499740e3314e3a49767c2b755d1db8bc16fec,96a512208fade6825da6aa8e2645f2a088d485d2..239bc16a1ddd61c9fd65d3d1f1284025fd69df2c
@@@ -110,10 -110,17 +110,10 @@@ struct kgd2kfd_calls 
  /**
   * struct kfd2kgd_calls
   *
 - * @init_sa_manager: Initialize an instance of the sa manager, used by
 - * amdkfd for all system memory allocations that are mapped to the GART
 - * address space
 + * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
 + * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
   *
 - * @fini_sa_manager: Releases all memory allocations for amdkfd that are
 - * handled by kgd sa manager
 - *
 - * @allocate_mem: Allocate a buffer from amdkfd's sa manager. The buffer can
 - * be used for mqds, hpds, kernel queue, fence and runlists
 - *
 - * @free_mem: Frees a buffer that was allocated by amdkfd's sa manager
 + * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
   *
   * @get_vmem_size: Retrieves (physical) size of VRAM
   *
   * @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp
   * scheduling mode. Only used for no cp scheduling mode.
   *
 - * @init_memory: Initializes memory apertures to fixed base/limit address
 - * and non cached memory types.
 - *
   * @init_pipeline: Initialized the compute pipelines.
   *
   * @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp
   * sceduling mode.
   *
 + * @hqd_sdma_load: Loads the SDMA mqd structure to a H/W SDMA hqd slot.
 + * used only for no HWS mode.
 + *
   * @hqd_is_occupies: Checks if a hqd slot is occupied.
   *
   * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
   *
 + * @hqd_sdma_is_occupied: Checks if an SDMA hqd slot is occupied.
 + *
 + * @hqd_sdma_destroy: Destructs and preempts the SDMA queue assigned to that
 + * SDMA hqd slot.
 + *
   * @get_fw_version: Returns FW versions from the header
   *
   * This structure contains function pointers to services that the kgd driver
   *
   */
  struct kfd2kgd_calls {
 -      /* Memory management. */
 -      int (*init_sa_manager)(struct kgd_dev *kgd, unsigned int size);
 -      void (*fini_sa_manager)(struct kgd_dev *kgd);
 -      int (*allocate_mem)(struct kgd_dev *kgd, size_t size, size_t alignment,
 -                      enum kgd_memory_pool pool, struct kgd_mem **mem);
 +      int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
 +                                      void **mem_obj, uint64_t *gpu_addr,
 +                                      void **cpu_ptr);
  
 -      void (*free_mem)(struct kgd_dev *kgd, struct kgd_mem *mem);
 +      void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
  
        uint64_t (*get_vmem_size)(struct kgd_dev *kgd);
        uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
        int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
                                        unsigned int vmid);
  
 -      int (*init_memory)(struct kgd_dev *kgd);
        int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
                                uint32_t hpd_size, uint64_t hpd_gpu_addr);
  
        int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr);
  
-       bool (*hqd_is_occupies)(struct kgd_dev *kgd, uint64_t queue_address,
 +      int (*hqd_sdma_load)(struct kgd_dev *kgd, void *mqd);
 +
+       bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id);
  
        int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id);
 +
 +      bool (*hqd_sdma_is_occupied)(struct kgd_dev *kgd, void *mqd);
 +
 +      int (*hqd_sdma_destroy)(struct kgd_dev *kgd, void *mqd,
 +                              unsigned int timeout);
 +
        uint16_t (*get_fw_version)(struct kgd_dev *kgd,
                                enum kgd_engine_type type);
  };
  
  bool kgd2kfd_init(unsigned interface_version,
 -                const struct kfd2kgd_calls *f2g,
 -                const struct kgd2kfd_calls **g2f);
 +              const struct kfd2kgd_calls *f2g,
 +              const struct kgd2kfd_calls **g2f);
  
 -#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
 +#endif        /* KGD_KFD_INTERFACE_H_INCLUDED */
index fd7a493df0de43d1c1e90816332b1c42a01d47ee,e9f891c432f837b8693df84158b0b2cdf715972e..54f2a275dba628c9f6555b7e3213b89e82fe03ad
  
  #define DRIVER_NAME           "i915"
  #define DRIVER_DESC           "Intel Graphics"
 -#define DRIVER_DATE           "20141121"
 +#define DRIVER_DATE           "20141219"
  
  #undef WARN_ON
 -#define WARN_ON(x)            WARN(x, "WARN_ON(" #x ")")
 +/* Many gcc seem to no see through this and fall over :( */
 +#if 0
 +#define WARN_ON(x) ({ \
 +      bool __i915_warn_cond = (x); \
 +      if (__builtin_constant_p(__i915_warn_cond)) \
 +              BUILD_BUG_ON(__i915_warn_cond); \
 +      WARN(__i915_warn_cond, "WARN_ON(" #x ")"); })
 +#else
 +#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
 +#endif
 +
 +#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
 +                           (long) (x), __func__);
 +
 +/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
 + * WARN_ON()) for hw state sanity checks to check for unexpected conditions
 + * which may not necessarily be a user visible problem.  This will either
 + * WARN() or DRM_ERROR() depending on the verbose_checks moduleparam, to
 + * enable distros and users to tailor their preferred amount of i915 abrt
 + * spam.
 + */
 +#define I915_STATE_WARN(condition, format...) ({                      \
 +      int __ret_warn_on = !!(condition);                              \
 +      if (unlikely(__ret_warn_on)) {                                  \
 +              if (i915.verbose_state_checks)                          \
 +                      __WARN_printf(format);                          \
 +              else                                                    \
 +                      DRM_ERROR(format);                              \
 +      }                                                               \
 +      unlikely(__ret_warn_on);                                        \
 +})
 +
 +#define I915_STATE_WARN_ON(condition) ({                              \
 +      int __ret_warn_on = !!(condition);                              \
 +      if (unlikely(__ret_warn_on)) {                                  \
 +              if (i915.verbose_state_checks)                          \
 +                      __WARN_printf("WARN_ON(" #condition ")\n");     \
 +              else                                                    \
 +                      DRM_ERROR("WARN_ON(" #condition ")\n");         \
 +      }                                                               \
 +      unlikely(__ret_warn_on);                                        \
 +})
  
  enum pipe {
        INVALID_PIPE = -1,
@@@ -1171,11 -1130,6 +1171,11 @@@ struct intel_l3_parity 
        int which_slice;
  };
  
 +struct i915_gem_batch_pool {
 +      struct drm_device *dev;
 +      struct list_head cache_list;
 +};
 +
  struct i915_gem_mm {
        /** Memory allocator for GTT stolen memory */
        struct drm_mm stolen;
         */
        struct list_head unbound_list;
  
 +      /*
 +       * A pool of objects to use as shadow copies of client batch buffers
 +       * when the command parser is enabled. Prevents the client from
 +       * modifying the batch contents after software parsing.
 +       */
 +      struct i915_gem_batch_pool batch_pool;
 +
        /** Usable portion of the GTT for GEM */
        unsigned long stolen_base; /* limited to low memory (32-bit) */
  
@@@ -1360,13 -1307,6 +1360,13 @@@ enum drrs_support_type 
        SEAMLESS_DRRS_SUPPORT = 2
  };
  
 +enum psr_lines_to_wait {
 +      PSR_0_LINES_TO_WAIT = 0,
 +      PSR_1_LINE_TO_WAIT,
 +      PSR_4_LINES_TO_WAIT,
 +      PSR_8_LINES_TO_WAIT
 +};
 +
  struct intel_vbt_data {
        struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
        struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
        int edp_bpp;
        struct edp_power_seq edp_pps;
  
 +      struct {
 +              bool full_link;
 +              bool require_aux_wakeup;
 +              int idle_frames;
 +              enum psr_lines_to_wait lines_to_wait;
 +              int tp1_wakeup_time;
 +              int tp2_tp3_wakeup_time;
 +      } psr;
 +
        struct {
                u16 pwm_freq_hz;
                bool present;
                bool active_low_pwm;
                u8 min_brightness;      /* min_brightness/255 of max */
 +              u8 controller;          /* brightness controller number */
        } backlight;
  
        /* MIPI DSI */
@@@ -1826,8 -1756,6 +1826,6 @@@ struct drm_i915_private 
         */
        struct workqueue_struct *dp_wq;
  
-       uint32_t bios_vgacntr;
        /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
        struct {
                int (*do_execbuf)(struct drm_device *dev, struct drm_file *file,
                void (*stop_ring)(struct intel_engine_cs *ring);
        } gt;
  
 +      uint32_t request_uniq;
 +
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@@ -1927,8 -1853,6 +1925,8 @@@ struct drm_i915_gem_object 
        /** Used in execbuf to temporarily hold a ref */
        struct list_head obj_exec_link;
  
 +      struct list_head batch_pool_list;
 +
        /**
         * This is set if the object is on the active lists (has pending
         * rendering and so a non-zero seqno), and is not set if it i s on
        void *dma_buf_vmapping;
        int vmapping_count;
  
 -      struct intel_engine_cs *ring;
 -
        /** Breadcrumb of last rendering to the buffer. */
 -      uint32_t last_read_seqno;
 -      uint32_t last_write_seqno;
 +      struct drm_i915_gem_request *last_read_req;
 +      struct drm_i915_gem_request *last_write_req;
        /** Breadcrumb of last fenced GPU access to the buffer. */
 -      uint32_t last_fenced_seqno;
 +      struct drm_i915_gem_request *last_fenced_req;
  
        /** Current tiling stride for the object, if it's tiled. */
        uint32_t stride;
        /** Record of address bit 17 of each page at last unbind. */
        unsigned long *bit_17;
  
 -      /** User space pin count and filp owning the pin */
 -      unsigned long user_pin_count;
 -      struct drm_file *pin_filp;
 -
        union {
                /** for phy allocated objects */
                struct drm_dma_handle *phys_handle;
@@@ -2043,14 -1973,11 +2041,14 @@@ void i915_gem_track_fb(struct drm_i915_
   * The request queue allows us to note sequence numbers that have been emitted
   * and may be associated with active buffers to be retired.
   *
 - * By keeping this list, we can avoid having to do questionable
 - * sequence-number comparisons on buffer last_rendering_seqnos, and associate
 - * an emission time with seqnos for tracking how far ahead of the GPU we are.
 + * By keeping this list, we can avoid having to do questionable sequence
 + * number comparisons on buffer last_read|write_seqno. It also allows an
 + * emission time to be associated with the request for tracking how far ahead
 + * of the GPU the submission is.
   */
  struct drm_i915_gem_request {
 +      struct kref ref;
 +
        /** On Which ring this request was generated */
        struct intel_engine_cs *ring;
  
        struct drm_i915_file_private *file_priv;
        /** file_priv list entry for this request */
        struct list_head client_list;
 +
 +      uint32_t uniq;
  };
  
 +void i915_gem_request_free(struct kref *req_ref);
 +
 +static inline uint32_t
 +i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
 +{
 +      return req ? req->seqno : 0;
 +}
 +
 +static inline struct intel_engine_cs *
 +i915_gem_request_get_ring(struct drm_i915_gem_request *req)
 +{
 +      return req ? req->ring : NULL;
 +}
 +
 +static inline void
 +i915_gem_request_reference(struct drm_i915_gem_request *req)
 +{
 +      kref_get(&req->ref);
 +}
 +
 +static inline void
 +i915_gem_request_unreference(struct drm_i915_gem_request *req)
 +{
 +      WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
 +      kref_put(&req->ref, i915_gem_request_free);
 +}
 +
 +static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
 +                                         struct drm_i915_gem_request *src)
 +{
 +      if (src)
 +              i915_gem_request_reference(src);
 +
 +      if (*pdst)
 +              i915_gem_request_unreference(*pdst);
 +
 +      *pdst = src;
 +}
 +
 +/*
 + * XXX: i915_gem_request_completed should be here but currently needs the
 + * definition of i915_seqno_passed() which is below. It will be moved in
 + * a later patch when the call to i915_seqno_passed() is obsoleted...
 + */
 +
  struct drm_i915_file_private {
        struct drm_i915_private *dev_priv;
        struct drm_file *file;
@@@ -2360,8 -2240,7 +2358,8 @@@ struct drm_i915_cmd_table 
  
  #define HAS_DDI(dev)          (INTEL_INFO(dev)->has_ddi)
  #define HAS_FPGA_DBG_UNCLAIMED(dev)   (INTEL_INFO(dev)->has_fpga_dbg)
 -#define HAS_PSR(dev)          (IS_HASWELL(dev) || IS_BROADWELL(dev))
 +#define HAS_PSR(dev)          (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
 +                               IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
  #define HAS_RUNTIME_PM(dev)   (IS_GEN6(dev) || IS_HASWELL(dev) || \
                                 IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
  #define HAS_RC6(dev)          (INTEL_INFO(dev)->gen >= 6)
@@@ -2431,7 -2310,6 +2429,7 @@@ struct i915_params 
        bool disable_vtd_wa;
        int use_mmio_flip;
        bool mmio_debug;
 +      bool verbose_state_checks;
  };
  extern struct i915_params i915 __read_mostly;
  
@@@ -2532,6 -2410,10 +2530,6 @@@ int i915_gem_execbuffer(struct drm_devi
                        struct drm_file *file_priv);
  int i915_gem_execbuffer2(struct drm_device *dev, void *data,
                         struct drm_file *file_priv);
 -int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
 -                     struct drm_file *file_priv);
 -int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
 -                       struct drm_file *file_priv);
  int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
  int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
@@@ -2576,23 -2458,10 +2574,23 @@@ void i915_gem_vma_destroy(struct i915_v
  #define PIN_GLOBAL 0x4
  #define PIN_OFFSET_BIAS 0x8
  #define PIN_OFFSET_MASK (~4095)
 +int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
 +                                        struct i915_address_space *vm,
 +                                        uint32_t alignment,
 +                                        uint64_t flags,
 +                                        const struct i915_ggtt_view *view);
 +static inline
  int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
                                     struct i915_address_space *vm,
                                     uint32_t alignment,
 -                                   uint64_t flags);
 +                                   uint64_t flags)
 +{
 +      return i915_gem_object_pin_view(obj, vm, alignment, flags,
 +                                              &i915_ggtt_view_normal);
 +}
 +
 +int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
 +                u32 flags);
  int __must_check i915_vma_unbind(struct i915_vma *vma);
  int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
  void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
@@@ -2641,18 -2510,6 +2639,18 @@@ i915_seqno_passed(uint32_t seq1, uint32
        return (int32_t)(seq1 - seq2) >= 0;
  }
  
 +static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
 +                                            bool lazy_coherency)
 +{
 +      u32 seqno;
 +
 +      BUG_ON(req == NULL);
 +
 +      seqno = req->ring->get_seqno(req->ring, lazy_coherency);
 +
 +      return i915_seqno_passed(seqno, req->seqno);
 +}
 +
  int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
  int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
  int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
@@@ -2668,7 -2525,7 +2666,7 @@@ bool i915_gem_retire_requests(struct dr
  void i915_gem_retire_requests_ring(struct intel_engine_cs *ring);
  int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
                                      bool interruptible);
 -int __must_check i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno);
 +int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req);
  
  static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
  {
@@@ -2711,15 -2568,17 +2709,15 @@@ int __must_check i915_gpu_idle(struct d
  int __must_check i915_gem_suspend(struct drm_device *dev);
  int __i915_add_request(struct intel_engine_cs *ring,
                       struct drm_file *file,
 -                     struct drm_i915_gem_object *batch_obj,
 -                     u32 *seqno);
 -#define i915_add_request(ring, seqno) \
 -      __i915_add_request(ring, NULL, NULL, seqno)
 -int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
 +                     struct drm_i915_gem_object *batch_obj);
 +#define i915_add_request(ring) \
 +      __i915_add_request(ring, NULL, NULL)
 +int __i915_wait_request(struct drm_i915_gem_request *req,
                        unsigned reset_counter,
                        bool interruptible,
                        s64 *timeout,
                        struct drm_i915_file_private *file_priv);
 -int __must_check i915_wait_seqno(struct intel_engine_cs *ring,
 -                               uint32_t seqno);
 +int __must_check i915_wait_request(struct drm_i915_gem_request *req);
  int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
  int __must_check
  i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@@ -2753,51 -2612,18 +2751,51 @@@ struct dma_buf *i915_gem_prime_export(s
  
  void i915_gem_restore_fences(struct drm_device *dev);
  
 +unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
 +                                     struct i915_address_space *vm,
 +                                     enum i915_ggtt_view_type view);
 +static inline
  unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
 -                                struct i915_address_space *vm);
 +                                struct i915_address_space *vm)
 +{
 +      return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
 +}
  bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
 +bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
 +                           struct i915_address_space *vm,
 +                           enum i915_ggtt_view_type view);
 +static inline
  bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
 -                      struct i915_address_space *vm);
 +                      struct i915_address_space *vm)
 +{
 +      return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
 +}
 +
  unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
                                struct i915_address_space *vm);
 +struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
 +                                        struct i915_address_space *vm,
 +                                        const struct i915_ggtt_view *view);
 +static inline
  struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 -                                   struct i915_address_space *vm);
 +                                   struct i915_address_space *vm)
 +{
 +      return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
 +}
 +
 +struct i915_vma *
 +i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
 +                                     struct i915_address_space *vm,
 +                                     const struct i915_ggtt_view *view);
 +
 +static inline
  struct i915_vma *
  i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
 -                                struct i915_address_space *vm);
 +                                struct i915_address_space *vm)
 +{
 +      return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
 +                                              &i915_ggtt_view_normal);
 +}
  
  struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
  static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
@@@ -2979,13 -2805,6 +2977,13 @@@ void i915_destroy_error_state(struct dr
  void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
  const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
  
 +/* i915_gem_batch_pool.c */
 +void i915_gem_batch_pool_init(struct drm_device *dev,
 +                            struct i915_gem_batch_pool *pool);
 +void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
 +struct drm_i915_gem_object*
 +i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
 +
  /* i915_cmd_parser.c */
  int i915_cmd_parser_get_version(void);
  int i915_cmd_parser_init_ring(struct intel_engine_cs *ring);
@@@ -2993,9 -2812,7 +2991,9 @@@ void i915_cmd_parser_fini_ring(struct i
  bool i915_needs_cmd_parser(struct intel_engine_cs *ring);
  int i915_parse_cmds(struct intel_engine_cs *ring,
                    struct drm_i915_gem_object *batch_obj,
 +                  struct drm_i915_gem_object *shadow_batch_obj,
                    u32 batch_start_offset,
 +                  u32 batch_len,
                    bool is_master);
  
  /* i915_suspend.c */
@@@ -3075,6 -2892,9 +3073,6 @@@ extern void intel_modeset_setup_hw_stat
                                         bool force_restore);
  extern void i915_redisable_vga(struct drm_device *dev);
  extern void i915_redisable_vga_power_on(struct drm_device *dev);
 -extern bool intel_fbc_enabled(struct drm_device *dev);
 -extern void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
 -extern void intel_disable_fbc(struct drm_device *dev);
  extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
  extern void intel_init_pch_refclk(struct drm_device *dev);
  extern void gen6_set_rps(struct drm_device *dev, u8 val);
@@@ -3250,11 -3070,4 +3248,11 @@@ wait_remaining_ms_from_jiffies(unsigne
        }
  }
  
 +static inline void i915_trace_irq_get(struct intel_engine_cs *ring,
 +                                    struct drm_i915_gem_request *req)
 +{
 +      if (ring->trace_irq_req == NULL && ring->irq_get(ring))
 +              i915_gem_request_assign(&ring->trace_irq_req, req);
 +}
 +
  #endif
index 3044fb324c8e9e255ab20d867af94af71e11bc11,76354d3ba925795e0377e197e48a42cbe538b93f..4e4d969d3b283ee67411289cb52d3fe0d1285487
@@@ -1048,6 -1048,7 +1048,7 @@@ in
  i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                      struct drm_file *file)
  {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_pwrite *args = data;
        struct drm_i915_gem_object *obj;
        int ret;
                        return -EFAULT;
        }
  
+       intel_runtime_pm_get(dev_priv);
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
-               return ret;
+               goto put_rpm;
  
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
        if (&obj->base == NULL) {
@@@ -1121,6 -1124,9 +1124,9 @@@ out
        drm_gem_object_unreference(&obj->base);
  unlock:
        mutex_unlock(&dev->struct_mutex);
+ put_rpm:
+       intel_runtime_pm_put(dev_priv);
        return ret;
  }
  
@@@ -1151,18 -1157,19 +1157,18 @@@ i915_gem_check_wedge(struct i915_gpu_er
  }
  
  /*
 - * Compare seqno against outstanding lazy request. Emit a request if they are
 - * equal.
 + * Compare arbitrary request against outstanding lazy request. Emit on match.
   */
  int
 -i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno)
 +i915_gem_check_olr(struct drm_i915_gem_request *req)
  {
        int ret;
  
 -      BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
 +      WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
  
        ret = 0;
 -      if (seqno == ring->outstanding_lazy_seqno)
 -              ret = i915_add_request(ring, NULL);
 +      if (req == req->ring->outstanding_lazy_request)
 +              ret = i915_add_request(req->ring);
  
        return ret;
  }
@@@ -1187,9 -1194,10 +1193,9 @@@ static bool can_wait_boost(struct drm_i
  }
  
  /**
 - * __i915_wait_seqno - wait until execution of seqno has finished
 - * @ring: the ring expected to report seqno
 - * @seqno: duh!
 - * @reset_counter: reset sequence associated with the given seqno
 + * __i915_wait_request - wait until execution of request has finished
 + * @req: duh!
 + * @reset_counter: reset sequence associated with the given request
   * @interruptible: do an interruptible wait (normally yes)
   * @timeout: in - how long to wait (NULL forever); out - how much time remaining
   *
   * reset_counter _must_ be read before, and an appropriate smp_rmb must be
   * inserted.
   *
 - * Returns 0 if the seqno was found within the alloted time. Else returns the
 + * Returns 0 if the request was found within the alloted time. Else returns the
   * errno with remaining time filled in timeout argument.
   */
 -int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
 +int __i915_wait_request(struct drm_i915_gem_request *req,
                        unsigned reset_counter,
                        bool interruptible,
                        s64 *timeout,
                        struct drm_i915_file_private *file_priv)
  {
 +      struct intel_engine_cs *ring = i915_gem_request_get_ring(req);
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        const bool irq_test_in_progress =
  
        WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled");
  
 -      if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
 +      if (i915_gem_request_completed(req, true))
                return 0;
  
        timeout_expire = timeout ?
                return -ENODEV;
  
        /* Record current time in case interrupted by signal, or wedged */
 -      trace_i915_gem_request_wait_begin(ring, seqno);
 +      trace_i915_gem_request_wait_begin(req);
        before = ktime_get_raw_ns();
        for (;;) {
                struct timer_list timer;
                        break;
                }
  
 -              if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) {
 +              if (i915_gem_request_completed(req, false)) {
                        ret = 0;
                        break;
                }
                }
        }
        now = ktime_get_raw_ns();
 -      trace_i915_gem_request_wait_end(ring, seqno);
 +      trace_i915_gem_request_wait_end(req);
  
        if (!irq_test_in_progress)
                ring->irq_put(ring);
  }
  
  /**
 - * Waits for a sequence number to be signaled, and cleans up the
 + * Waits for a request to be signaled, and cleans up the
   * request and object lists appropriately for that event.
   */
  int
 -i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno)
 +i915_wait_request(struct drm_i915_gem_request *req)
  {
 -      struct drm_device *dev = ring->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      bool interruptible = dev_priv->mm.interruptible;
 +      struct drm_device *dev;
 +      struct drm_i915_private *dev_priv;
 +      bool interruptible;
        unsigned reset_counter;
        int ret;
  
 +      BUG_ON(req == NULL);
 +
 +      dev = req->ring->dev;
 +      dev_priv = dev->dev_private;
 +      interruptible = dev_priv->mm.interruptible;
 +
        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 -      BUG_ON(seqno == 0);
  
        ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible);
        if (ret)
                return ret;
  
 -      ret = i915_gem_check_olr(ring, seqno);
 +      ret = i915_gem_check_olr(req);
        if (ret)
                return ret;
  
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 -      return __i915_wait_seqno(ring, seqno, reset_counter, interruptible,
 -                               NULL, NULL);
 +      i915_gem_request_reference(req);
 +      ret = __i915_wait_request(req, reset_counter,
 +                                interruptible, NULL, NULL);
 +      i915_gem_request_unreference(req);
 +      return ret;
  }
  
  static int
@@@ -1362,11 -1361,11 +1368,11 @@@ i915_gem_object_wait_rendering__tail(st
        /* Manually manage the write flush as we may have not yet
         * retired the buffer.
         *
 -       * Note that the last_write_seqno is always the earlier of
 -       * the two (read/write) seqno, so if we haved successfully waited,
 +       * Note that the last_write_req is always the earlier of
 +       * the two (read/write) requests, so if we haved successfully waited,
         * we know we have passed the last write.
         */
 -      obj->last_write_seqno = 0;
 +      i915_gem_request_assign(&obj->last_write_req, NULL);
  
        return 0;
  }
@@@ -1379,14 -1378,15 +1385,14 @@@ static __must_check in
  i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
                               bool readonly)
  {
 -      struct intel_engine_cs *ring = obj->ring;
 -      u32 seqno;
 +      struct drm_i915_gem_request *req;
        int ret;
  
 -      seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
 -      if (seqno == 0)
 +      req = readonly ? obj->last_write_req : obj->last_read_req;
 +      if (!req)
                return 0;
  
 -      ret = i915_wait_seqno(ring, seqno);
 +      ret = i915_wait_request(req);
        if (ret)
                return ret;
  
@@@ -1401,33 -1401,33 +1407,33 @@@ i915_gem_object_wait_rendering__nonbloc
                                            struct drm_i915_file_private *file_priv,
                                            bool readonly)
  {
 +      struct drm_i915_gem_request *req;
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_engine_cs *ring = obj->ring;
        unsigned reset_counter;
 -      u32 seqno;
        int ret;
  
        BUG_ON(!mutex_is_locked(&dev->struct_mutex));
        BUG_ON(!dev_priv->mm.interruptible);
  
 -      seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
 -      if (seqno == 0)
 +      req = readonly ? obj->last_write_req : obj->last_read_req;
 +      if (!req)
                return 0;
  
        ret = i915_gem_check_wedge(&dev_priv->gpu_error, true);
        if (ret)
                return ret;
  
 -      ret = i915_gem_check_olr(ring, seqno);
 +      ret = i915_gem_check_olr(req);
        if (ret)
                return ret;
  
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 +      i915_gem_request_reference(req);
        mutex_unlock(&dev->struct_mutex);
 -      ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL,
 -                              file_priv);
 +      ret = __i915_wait_request(req, reset_counter, true, NULL, file_priv);
        mutex_lock(&dev->struct_mutex);
 +      i915_gem_request_unreference(req);
        if (ret)
                return ret;
  
@@@ -2256,18 -2256,14 +2262,18 @@@ static voi
  i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
                               struct intel_engine_cs *ring)
  {
 -      u32 seqno = intel_ring_get_seqno(ring);
 +      struct drm_i915_gem_request *req;
 +      struct intel_engine_cs *old_ring;
  
        BUG_ON(ring == NULL);
 -      if (obj->ring != ring && obj->last_write_seqno) {
 -              /* Keep the seqno relative to the current ring */
 -              obj->last_write_seqno = seqno;
 +
 +      req = intel_ring_get_request(ring);
 +      old_ring = i915_gem_request_get_ring(obj->last_read_req);
 +
 +      if (old_ring != ring && obj->last_write_req) {
 +              /* Keep the request relative to the current ring */
 +              i915_gem_request_assign(&obj->last_write_req, req);
        }
 -      obj->ring = ring;
  
        /* Add a reference if we're newly entering the active list. */
        if (!obj->active) {
  
        list_move_tail(&obj->ring_list, &ring->active_list);
  
 -      obj->last_read_seqno = seqno;
 +      i915_gem_request_assign(&obj->last_read_req, req);
  }
  
  void i915_vma_move_to_active(struct i915_vma *vma,
  static void
  i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
  {
 -      struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 -      struct i915_address_space *vm;
        struct i915_vma *vma;
  
        BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
        BUG_ON(!obj->active);
  
 -      list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
 -              vma = i915_gem_obj_to_vma(obj, vm);
 -              if (vma && !list_empty(&vma->mm_list))
 -                      list_move_tail(&vma->mm_list, &vm->inactive_list);
 +      list_for_each_entry(vma, &obj->vma_list, vma_link) {
 +              if (!list_empty(&vma->mm_list))
 +                      list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
        }
  
        intel_fb_obj_flush(obj, true);
  
        list_del_init(&obj->ring_list);
 -      obj->ring = NULL;
  
 -      obj->last_read_seqno = 0;
 -      obj->last_write_seqno = 0;
 +      i915_gem_request_assign(&obj->last_read_req, NULL);
 +      i915_gem_request_assign(&obj->last_write_req, NULL);
        obj->base.write_domain = 0;
  
 -      obj->last_fenced_seqno = 0;
 +      i915_gem_request_assign(&obj->last_fenced_req, NULL);
  
        obj->active = 0;
        drm_gem_object_unreference(&obj->base);
  static void
  i915_gem_object_retire(struct drm_i915_gem_object *obj)
  {
 -      struct intel_engine_cs *ring = obj->ring;
 -
 -      if (ring == NULL)
 +      if (obj->last_read_req == NULL)
                return;
  
 -      if (i915_seqno_passed(ring->get_seqno(ring, true),
 -                            obj->last_read_seqno))
 +      if (i915_gem_request_completed(obj->last_read_req, true))
                i915_gem_object_move_to_inactive(obj);
  }
  
@@@ -2398,7 -2401,8 +2404,7 @@@ i915_gem_get_seqno(struct drm_device *d
  
  int __i915_add_request(struct intel_engine_cs *ring,
                       struct drm_file *file,
 -                     struct drm_i915_gem_object *obj,
 -                     u32 *out_seqno)
 +                     struct drm_i915_gem_object *obj)
  {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_request *request;
        u32 request_ring_position, request_start;
        int ret;
  
 -      request = ring->preallocated_lazy_request;
 +      request = ring->outstanding_lazy_request;
        if (WARN_ON(request == NULL))
                return -ENOMEM;
  
                        return ret;
        }
  
 -      request->seqno = intel_ring_get_seqno(ring);
 -      request->ring = ring;
        request->head = request_start;
        request->tail = request_ring_position;
  
                spin_unlock(&file_priv->mm.lock);
        }
  
 -      trace_i915_gem_request_add(ring, request->seqno);
 -      ring->outstanding_lazy_seqno = 0;
 -      ring->preallocated_lazy_request = NULL;
 +      trace_i915_gem_request_add(request);
 +      ring->outstanding_lazy_request = NULL;
  
        i915_queue_hangcheck(ring->dev);
  
                           round_jiffies_up_relative(HZ));
        intel_mark_busy(dev_priv->dev);
  
 -      if (out_seqno)
 -              *out_seqno = request->seqno;
        return 0;
  }
  
@@@ -2559,39 -2568,33 +2565,39 @@@ static void i915_set_reset_status(struc
  
  static void i915_gem_free_request(struct drm_i915_gem_request *request)
  {
 -      struct intel_context *ctx = request->ctx;
 -
        list_del(&request->list);
        i915_gem_request_remove_from_client(request);
  
 +      i915_gem_request_unreference(request);
 +}
 +
 +void i915_gem_request_free(struct kref *req_ref)
 +{
 +      struct drm_i915_gem_request *req = container_of(req_ref,
 +                                               typeof(*req), ref);
 +      struct intel_context *ctx = req->ctx;
 +
        if (ctx) {
                if (i915.enable_execlists) {
 -                      struct intel_engine_cs *ring = request->ring;
 +                      struct intel_engine_cs *ring = req->ring;
  
                        if (ctx != ring->default_context)
                                intel_lr_context_unpin(ring, ctx);
                }
 +
                i915_gem_context_unreference(ctx);
        }
 -      kfree(request);
 +
 +      kfree(req);
  }
  
  struct drm_i915_gem_request *
  i915_gem_find_active_request(struct intel_engine_cs *ring)
  {
        struct drm_i915_gem_request *request;
 -      u32 completed_seqno;
 -
 -      completed_seqno = ring->get_seqno(ring, false);
  
        list_for_each_entry(request, &ring->request_list, list) {
 -              if (i915_seqno_passed(completed_seqno, request->seqno))
 +              if (i915_gem_request_completed(request, false))
                        continue;
  
                return request;
@@@ -2666,8 -2669,10 +2672,8 @@@ static void i915_gem_reset_ring_cleanup
                i915_gem_free_request(request);
        }
  
 -      /* These may not have been flush before the reset, do so now */
 -      kfree(ring->preallocated_lazy_request);
 -      ring->preallocated_lazy_request = NULL;
 -      ring->outstanding_lazy_seqno = 0;
 +      /* This may not have been flushed before the reset, so clean it now */
 +      i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
  }
  
  void i915_gem_restore_fences(struct drm_device *dev)
@@@ -2719,11 -2724,15 +2725,11 @@@ void i915_gem_reset(struct drm_device *
  void
  i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
  {
 -      uint32_t seqno;
 -
        if (list_empty(&ring->request_list))
                return;
  
        WARN_ON(i915_verify_lists(ring->dev));
  
 -      seqno = ring->get_seqno(ring, true);
 -
        /* Move any buffers on the active list that are no longer referenced
         * by the ringbuffer to the flushing/inactive lists as appropriate,
         * before we free the context associated with the requests.
                                      struct drm_i915_gem_object,
                                      ring_list);
  
 -              if (!i915_seqno_passed(seqno, obj->last_read_seqno))
 +              if (!i915_gem_request_completed(obj->last_read_req, true))
                        break;
  
                i915_gem_object_move_to_inactive(obj);
                                           struct drm_i915_gem_request,
                                           list);
  
 -              if (!i915_seqno_passed(seqno, request->seqno))
 +              if (!i915_gem_request_completed(request, true))
                        break;
  
 -              trace_i915_gem_request_retire(ring, request->seqno);
 +              trace_i915_gem_request_retire(request);
  
                /* This is one of the few common intersection points
                 * between legacy ringbuffer submission and execlists:
                i915_gem_free_request(request);
        }
  
 -      if (unlikely(ring->trace_irq_seqno &&
 -                   i915_seqno_passed(seqno, ring->trace_irq_seqno))) {
 +      if (unlikely(ring->trace_irq_req &&
 +                   i915_gem_request_completed(ring->trace_irq_req, true))) {
                ring->irq_put(ring);
 -              ring->trace_irq_seqno = 0;
 +              i915_gem_request_assign(&ring->trace_irq_req, NULL);
        }
  
        WARN_ON(i915_verify_lists(ring->dev));
@@@ -2851,17 -2860,14 +2857,17 @@@ i915_gem_idle_work_handler(struct work_
  static int
  i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
  {
 +      struct intel_engine_cs *ring;
        int ret;
  
        if (obj->active) {
 -              ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno);
 +              ring = i915_gem_request_get_ring(obj->last_read_req);
 +
 +              ret = i915_gem_check_olr(obj->last_read_req);
                if (ret)
                        return ret;
  
 -              i915_gem_retire_requests_ring(obj->ring);
 +              i915_gem_retire_requests_ring(ring);
        }
  
        return 0;
@@@ -2895,8 -2901,9 +2901,8 @@@ i915_gem_wait_ioctl(struct drm_device *
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_wait *args = data;
        struct drm_i915_gem_object *obj;
 -      struct intel_engine_cs *ring = NULL;
 +      struct drm_i915_gem_request *req;
        unsigned reset_counter;
 -      u32 seqno = 0;
        int ret = 0;
  
        if (args->flags != 0)
        if (ret)
                goto out;
  
 -      if (obj->active) {
 -              seqno = obj->last_read_seqno;
 -              ring = obj->ring;
 -      }
 +      if (!obj->active || !obj->last_read_req)
 +              goto out;
  
 -      if (seqno == 0)
 -               goto out;
 +      req = obj->last_read_req;
  
        /* Do this after OLR check to make sure we make forward progress polling
         * on this IOCTL with a timeout <=0 (like busy ioctl)
  
        drm_gem_object_unreference(&obj->base);
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 +      i915_gem_request_reference(req);
        mutex_unlock(&dev->struct_mutex);
  
 -      return __i915_wait_seqno(ring, seqno, reset_counter, true,
 -                               &args->timeout_ns, file->driver_priv);
 +      ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns,
 +                                file->driver_priv);
 +      mutex_lock(&dev->struct_mutex);
 +      i915_gem_request_unreference(req);
 +      mutex_unlock(&dev->struct_mutex);
 +      return ret;
  
  out:
        drm_gem_object_unreference(&obj->base);
  i915_gem_object_sync(struct drm_i915_gem_object *obj,
                     struct intel_engine_cs *to)
  {
 -      struct intel_engine_cs *from = obj->ring;
 +      struct intel_engine_cs *from;
        u32 seqno;
        int ret, idx;
  
 +      from = i915_gem_request_get_ring(obj->last_read_req);
 +
        if (from == NULL || to == from)
                return 0;
  
  
        idx = intel_ring_sync_index(from, to);
  
 -      seqno = obj->last_read_seqno;
 +      seqno = i915_gem_request_get_seqno(obj->last_read_req);
        /* Optimization: Avoid semaphore sync when we are sure we already
         * waited for an object with higher seqno */
        if (seqno <= from->semaphore.sync_seqno[idx])
                return 0;
  
 -      ret = i915_gem_check_olr(obj->ring, seqno);
 +      ret = i915_gem_check_olr(obj->last_read_req);
        if (ret)
                return ret;
  
 -      trace_i915_gem_ring_sync_to(from, to, seqno);
 +      trace_i915_gem_ring_sync_to(from, to, obj->last_read_req);
        ret = to->semaphore.sync_to(to, from, seqno);
        if (!ret)
 -              /* We use last_read_seqno because sync_to()
 +              /* We use last_read_req because sync_to()
                 * might have just caused seqno wrap under
                 * the radar.
                 */
 -              from->semaphore.sync_seqno[idx] = obj->last_read_seqno;
 +              from->semaphore.sync_seqno[idx] =
 +                              i915_gem_request_get_seqno(obj->last_read_req);
  
        return ret;
  }
@@@ -3052,8 -3054,10 +3058,8 @@@ int i915_vma_unbind(struct i915_vma *vm
         * cause memory corruption through use-after-free.
         */
  
 -      /* Throw away the active reference before moving to the unbound list */
 -      i915_gem_object_retire(obj);
 -
 -      if (i915_is_ggtt(vma->vm)) {
 +      if (i915_is_ggtt(vma->vm) &&
 +          vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
                i915_gem_object_finish_gtt(obj);
  
                /* release the fence reg _after_ flushing */
        vma->unbind_vma(vma);
  
        list_del_init(&vma->mm_list);
 -      if (i915_is_ggtt(vma->vm))
 -              obj->map_and_fenceable = false;
 +      if (i915_is_ggtt(vma->vm)) {
 +              if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
 +                      obj->map_and_fenceable = false;
 +              } else if (vma->ggtt_view.pages) {
 +                      sg_free_table(vma->ggtt_view.pages);
 +                      kfree(vma->ggtt_view.pages);
 +                      vma->ggtt_view.pages = NULL;
 +              }
 +      }
  
        drm_mm_remove_node(&vma->node);
        i915_gem_vma_destroy(vma);
        /* Since the unbound list is global, only move to that list if
         * no more VMAs exist. */
        if (list_empty(&obj->vma_list)) {
 +              /* Throw away the active reference before
 +               * moving to the unbound list. */
 +              i915_gem_object_retire(obj);
 +
                i915_gem_gtt_finish_object(obj);
                list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
        }
@@@ -3270,12 -3263,17 +3276,12 @@@ static void i915_gem_write_fence(struc
             "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
             obj->stride, obj->tiling_mode);
  
 -      switch (INTEL_INFO(dev)->gen) {
 -      case 9:
 -      case 8:
 -      case 7:
 -      case 6:
 -      case 5:
 -      case 4: i965_write_fence_reg(dev, reg, obj); break;
 -      case 3: i915_write_fence_reg(dev, reg, obj); break;
 -      case 2: i830_write_fence_reg(dev, reg, obj); break;
 -      default: BUG();
 -      }
 +      if (IS_GEN2(dev))
 +              i830_write_fence_reg(dev, reg, obj);
 +      else if (IS_GEN3(dev))
 +              i915_write_fence_reg(dev, reg, obj);
 +      else if (INTEL_INFO(dev)->gen >= 4)
 +              i965_write_fence_reg(dev, reg, obj);
  
        /* And similarly be paranoid that no direct access to this region
         * is reordered to before the fence is installed.
@@@ -3314,12 -3312,12 +3320,12 @@@ static void i915_gem_object_update_fenc
  static int
  i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
  {
 -      if (obj->last_fenced_seqno) {
 -              int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
 +      if (obj->last_fenced_req) {
 +              int ret = i915_wait_request(obj->last_fenced_req);
                if (ret)
                        return ret;
  
 -              obj->last_fenced_seqno = 0;
 +              i915_gem_request_assign(&obj->last_fenced_req, NULL);
        }
  
        return 0;
@@@ -3492,8 -3490,7 +3498,8 @@@ static struct i915_vma 
  i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
                           unsigned alignment,
 -                         uint64_t flags)
 +                         uint64_t flags,
 +                         const struct i915_ggtt_view *view)
  {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        i915_gem_object_pin_pages(obj);
  
 -      vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
 +      vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
        if (IS_ERR(vma))
                goto err_unpin;
  
@@@ -3573,19 -3570,15 +3579,19 @@@ search_free
        if (ret)
                goto err_remove_node;
  
 +      trace_i915_vma_bind(vma, flags);
 +      ret = i915_vma_bind(vma, obj->cache_level,
 +                          flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
 +      if (ret)
 +              goto err_finish_gtt;
 +
        list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
        list_add_tail(&vma->mm_list, &vm->inactive_list);
  
 -      trace_i915_vma_bind(vma, flags);
 -      vma->bind_vma(vma, obj->cache_level,
 -                    flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
 -
        return vma;
  
 +err_finish_gtt:
 +      i915_gem_gtt_finish_object(obj);
  err_remove_node:
        drm_mm_remove_node(&vma->node);
  err_free_vma:
@@@ -3788,12 -3781,9 +3794,12 @@@ int i915_gem_object_set_cache_level(str
                }
  
                list_for_each_entry(vma, &obj->vma_list, vma_link)
 -                      if (drm_mm_node_allocated(&vma->node))
 -                              vma->bind_vma(vma, cache_level,
 -                                              vma->bound & GLOBAL_BIND);
 +                      if (drm_mm_node_allocated(&vma->node)) {
 +                              ret = i915_vma_bind(vma, cache_level,
 +                                                  vma->bound & GLOBAL_BIND);
 +                              if (ret)
 +                                      return ret;
 +                      }
        }
  
        list_for_each_entry(vma, &obj->vma_list, vma_link)
@@@ -3912,14 -3902,18 +3918,14 @@@ static bool is_pin_display(struct drm_i
        if (!vma)
                return false;
  
 -      /* There are 3 sources that pin objects:
 +      /* There are 2 sources that pin objects:
         *   1. The display engine (scanouts, sprites, cursors);
         *   2. Reservations for execbuffer;
 -       *   3. The user.
         *
         * We can ignore reservations as we hold the struct_mutex and
 -       * are only called outside of the reservation path.  The user
 -       * can only increment pin_count once, and so if after
 -       * subtracting the potential reference by the user, any pin_count
 -       * remains, it must be due to another use by the display engine.
 +       * are only called outside of the reservation path.
         */
 -      return vma->pin_count - !!obj->user_pin_count;
 +      return vma->pin_count;
  }
  
  /*
@@@ -3936,7 -3930,7 +3942,7 @@@ i915_gem_object_pin_to_display_plane(st
        bool was_pin_display;
        int ret;
  
 -      if (pipelined != obj->ring) {
 +      if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
                ret = i915_gem_object_sync(obj, pipelined);
                if (ret)
                        return ret;
@@@ -4088,8 -4082,10 +4094,8 @@@ i915_gem_ring_throttle(struct drm_devic
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_file_private *file_priv = file->driver_priv;
        unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
 -      struct drm_i915_gem_request *request;
 -      struct intel_engine_cs *ring = NULL;
 +      struct drm_i915_gem_request *request, *target = NULL;
        unsigned reset_counter;
 -      u32 seqno = 0;
        int ret;
  
        ret = i915_gem_wait_for_error(&dev_priv->gpu_error);
                if (time_after_eq(request->emitted_jiffies, recent_enough))
                        break;
  
 -              ring = request->ring;
 -              seqno = request->seqno;
 +              target = request;
        }
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 +      if (target)
 +              i915_gem_request_reference(target);
        spin_unlock(&file_priv->mm.lock);
  
 -      if (seqno == 0)
 +      if (target == NULL)
                return 0;
  
 -      ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, NULL);
 +      ret = __i915_wait_request(target, reset_counter, true, NULL, NULL);
        if (ret == 0)
                queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
  
 +      mutex_lock(&dev->struct_mutex);
 +      i915_gem_request_unreference(target);
 +      mutex_unlock(&dev->struct_mutex);
 +
        return ret;
  }
  
@@@ -4146,11 -4137,10 +4152,11 @@@ i915_vma_misplaced(struct i915_vma *vma
  }
  
  int
 -i915_gem_object_pin(struct drm_i915_gem_object *obj,
 -                  struct i915_address_space *vm,
 -                  uint32_t alignment,
 -                  uint64_t flags)
 +i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
 +                       struct i915_address_space *vm,
 +                       uint32_t alignment,
 +                       uint64_t flags,
 +                       const struct i915_ggtt_view *view)
  {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        struct i915_vma *vma;
        if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
                return -EINVAL;
  
 -      vma = i915_gem_obj_to_vma(obj, vm);
 +      vma = i915_gem_obj_to_vma_view(obj, vm, view);
        if (vma) {
                if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
                        return -EBUSY;
                             "bo is already pinned with incorrect alignment:"
                             " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
 -                           i915_gem_obj_offset(obj, vm), alignment,
 +                           i915_gem_obj_offset_view(obj, vm, view->type),
 +                           alignment,
                             !!(flags & PIN_MAPPABLE),
                             obj->map_and_fenceable);
                        ret = i915_vma_unbind(vma);
  
        bound = vma ? vma->bound : 0;
        if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
 -              vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags);
 +              vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
 +                                               flags, view);
                if (IS_ERR(vma))
                        return PTR_ERR(vma);
        }
  
 -      if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND))
 -              vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
 +      if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
 +              ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
 +              if (ret)
 +                      return ret;
 +      }
  
        if ((bound ^ vma->bound) & GLOBAL_BIND) {
                bool mappable, fenceable;
@@@ -4271,6 -4256,102 +4277,6 @@@ i915_gem_object_unpin_fence(struct drm_
        }
  }
  
 -int
 -i915_gem_pin_ioctl(struct drm_device *dev, void *data,
 -                 struct drm_file *file)
 -{
 -      struct drm_i915_gem_pin *args = data;
 -      struct drm_i915_gem_object *obj;
 -      int ret;
 -
 -      if (drm_core_check_feature(dev, DRIVER_MODESET))
 -              return -ENODEV;
 -
 -      ret = i915_mutex_lock_interruptible(dev);
 -      if (ret)
 -              return ret;
 -
 -      obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 -      if (&obj->base == NULL) {
 -              ret = -ENOENT;
 -              goto unlock;
 -      }
 -
 -      if (obj->madv != I915_MADV_WILLNEED) {
 -              DRM_DEBUG("Attempting to pin a purgeable buffer\n");
 -              ret = -EFAULT;
 -              goto out;
 -      }
 -
 -      if (obj->pin_filp != NULL && obj->pin_filp != file) {
 -              DRM_DEBUG("Already pinned in i915_gem_pin_ioctl(): %d\n",
 -                        args->handle);
 -              ret = -EINVAL;
 -              goto out;
 -      }
 -
 -      if (obj->user_pin_count == ULONG_MAX) {
 -              ret = -EBUSY;
 -              goto out;
 -      }
 -
 -      if (obj->user_pin_count == 0) {
 -              ret = i915_gem_obj_ggtt_pin(obj, args->alignment, PIN_MAPPABLE);
 -              if (ret)
 -                      goto out;
 -      }
 -
 -      obj->user_pin_count++;
 -      obj->pin_filp = file;
 -
 -      args->offset = i915_gem_obj_ggtt_offset(obj);
 -out:
 -      drm_gem_object_unreference(&obj->base);
 -unlock:
 -      mutex_unlock(&dev->struct_mutex);
 -      return ret;
 -}
 -
 -int
 -i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
 -                   struct drm_file *file)
 -{
 -      struct drm_i915_gem_pin *args = data;
 -      struct drm_i915_gem_object *obj;
 -      int ret;
 -
 -      if (drm_core_check_feature(dev, DRIVER_MODESET))
 -              return -ENODEV;
 -
 -      ret = i915_mutex_lock_interruptible(dev);
 -      if (ret)
 -              return ret;
 -
 -      obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
 -      if (&obj->base == NULL) {
 -              ret = -ENOENT;
 -              goto unlock;
 -      }
 -
 -      if (obj->pin_filp != file) {
 -              DRM_DEBUG("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
 -                        args->handle);
 -              ret = -EINVAL;
 -              goto out;
 -      }
 -      obj->user_pin_count--;
 -      if (obj->user_pin_count == 0) {
 -              obj->pin_filp = NULL;
 -              i915_gem_object_ggtt_unpin(obj);
 -      }
 -
 -out:
 -      drm_gem_object_unreference(&obj->base);
 -unlock:
 -      mutex_unlock(&dev->struct_mutex);
 -      return ret;
 -}
 -
  int
  i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                    struct drm_file *file)
        ret = i915_gem_object_flush_active(obj);
  
        args->busy = obj->active;
 -      if (obj->ring) {
 +      if (obj->last_read_req) {
 +              struct intel_engine_cs *ring;
                BUILD_BUG_ON(I915_NUM_RINGS > 16);
 -              args->busy |= intel_ring_flag(obj->ring) << 16;
 +              ring = i915_gem_request_get_ring(obj->last_read_req);
 +              args->busy |= intel_ring_flag(ring) << 16;
        }
  
        drm_gem_object_unreference(&obj->base);
@@@ -4381,7 -4460,6 +4387,7 @@@ void i915_gem_object_init(struct drm_i9
        INIT_LIST_HEAD(&obj->ring_list);
        INIT_LIST_HEAD(&obj->obj_exec_link);
        INIT_LIST_HEAD(&obj->vma_list);
 +      INIT_LIST_HEAD(&obj->batch_pool_list);
  
        obj->ops = ops;
  
@@@ -4537,13 -4615,12 +4543,13 @@@ void i915_gem_free_object(struct drm_ge
        intel_runtime_pm_put(dev_priv);
  }
  
 -struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 -                                   struct i915_address_space *vm)
 +struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
 +                                        struct i915_address_space *vm,
 +                                        const struct i915_ggtt_view *view)
  {
        struct i915_vma *vma;
        list_for_each_entry(vma, &obj->vma_list, vma_link)
 -              if (vma->vm == vm)
 +              if (vma->vm == vm && vma->ggtt_view.type == view->type)
                        return vma;
  
        return NULL;
@@@ -4603,11 -4680,6 +4609,11 @@@ i915_gem_suspend(struct drm_device *dev
        cancel_delayed_work_sync(&dev_priv->mm.retire_work);
        flush_delayed_work(&dev_priv->mm.idle_work);
  
 +      /* Assert that we sucessfully flushed all the work and
 +       * reset the GPU back to its idle, low power state.
 +       */
 +      WARN_ON(dev_priv->mm.busy);
 +
        return 0;
  
  err:
@@@ -4719,6 -4791,14 +4725,6 @@@ int i915_gem_init_rings(struct drm_devi
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
  
 -      /*
 -       * At least 830 can leave some of the unused rings
 -       * "active" (ie. head != tail) after resume which
 -       * will prevent c3 entry. Makes sure all unused rings
 -       * are totally idle.
 -       */
 -      init_unused_rings(dev);
 -
        ret = intel_init_render_ring_buffer(dev);
        if (ret)
                return ret;
@@@ -4771,7 -4851,6 +4777,7 @@@ in
  i915_gem_init_hw(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct intel_engine_cs *ring;
        int ret, i;
  
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
  
        i915_gem_init_swizzling(dev);
  
 -      ret = dev_priv->gt.init_rings(dev);
 -      if (ret)
 -              return ret;
 +      /*
 +       * At least 830 can leave some of the unused rings
 +       * "active" (ie. head != tail) after resume which
 +       * will prevent c3 entry. Makes sure all unused rings
 +       * are totally idle.
 +       */
 +      init_unused_rings(dev);
 +
 +      for_each_ring(ring, dev_priv, i) {
 +              ret = ring->init_hw(ring);
 +              if (ret)
 +                      return ret;
 +      }
  
        for (i = 0; i < NUM_L3_SLICES(dev); i++)
                i915_gem_l3_remap(&dev_priv->ring[RCS], i);
@@@ -4870,18 -4939,18 +4876,18 @@@ int i915_gem_init(struct drm_device *de
        }
  
        ret = i915_gem_init_userptr(dev);
 -      if (ret) {
 -              mutex_unlock(&dev->struct_mutex);
 -              return ret;
 -      }
 +      if (ret)
 +              goto out_unlock;
  
        i915_gem_init_global_gtt(dev);
  
        ret = i915_gem_context_init(dev);
 -      if (ret) {
 -              mutex_unlock(&dev->struct_mutex);
 -              return ret;
 -      }
 +      if (ret)
 +              goto out_unlock;
 +
 +      ret = dev_priv->gt.init_rings(dev);
 +      if (ret)
 +              goto out_unlock;
  
        ret = i915_gem_init_hw(dev);
        if (ret == -EIO) {
                atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
                ret = 0;
        }
 +
 +out_unlock:
        mutex_unlock(&dev->struct_mutex);
  
        return ret;
@@@ -4995,8 -5062,6 +5001,8 @@@ i915_gem_load(struct drm_device *dev
        dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
        register_oom_notifier(&dev_priv->mm.oom_notifier);
  
 +      i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
 +
        mutex_init(&dev_priv->fb_tracking.lock);
  }
  
@@@ -5090,7 -5155,7 +5096,7 @@@ static bool mutex_is_locked_by(struct m
        if (!mutex_is_locked(mutex))
                return false;
  
- #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
+ #if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
        return mutex->owner == task;
  #else
        /* Since UP may be pre-empted, we cannot assume that we own the lock */
@@@ -5157,9 -5222,8 +5163,9 @@@ i915_gem_shrinker_count(struct shrinke
  }
  
  /* All the new VM stuff */
 -unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
 -                                struct i915_address_space *vm)
 +unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
 +                                     struct i915_address_space *vm,
 +                                     enum i915_ggtt_view_type view)
  {
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
        WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
  
        list_for_each_entry(vma, &o->vma_list, vma_link) {
 -              if (vma->vm == vm)
 +              if (vma->vm == vm && vma->ggtt_view.type == view)
                        return vma->node.start;
  
        }
        return -1;
  }
  
 -bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
 -                      struct i915_address_space *vm)
 +bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
 +                           struct i915_address_space *vm,
 +                           enum i915_ggtt_view_type view)
  {
        struct i915_vma *vma;
  
        list_for_each_entry(vma, &o->vma_list, vma_link)
 -              if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
 +              if (vma->vm == vm &&
 +                  vma->ggtt_view.type == view &&
 +                  drm_mm_node_allocated(&vma->node))
                        return true;
  
        return false;
@@@ -5317,13 -5378,11 +5323,13 @@@ i915_gem_shrinker_oom(struct notifier_b
  
  struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
  {
 +      struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
        struct i915_vma *vma;
  
 -      vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
 -      if (vma->vm != i915_obj_to_ggtt(obj))
 -              return NULL;
 +      list_for_each_entry(vma, &obj->vma_list, vma_link)
 +              if (vma->vm == ggtt &&
 +                  vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
 +                      return vma;
  
 -      return vma;
 +      return NULL;
  }
index 5d837735a3c22ccddee7fbd407345ccd1f2f0110,b051a238baf9338cb3e47a57ae31d6f1b540d006..818ab4e9dabc0201a68be2471a6f541826d7a23b
@@@ -183,8 -183,6 +183,8 @@@ static void ilk_update_gt_irq(struct dr
  {
        assert_spin_locked(&dev_priv->irq_lock);
  
 +      WARN_ON(enabled_irq_mask & ~interrupt_mask);
 +
        if (WARN_ON(!intel_irqs_enabled(dev_priv)))
                return;
  
@@@ -231,8 -229,6 +231,8 @@@ static void snb_update_pm_irq(struct dr
  {
        uint32_t new_val;
  
 +      WARN_ON(enabled_irq_mask & ~interrupt_mask);
 +
        assert_spin_locked(&dev_priv->irq_lock);
  
        new_val = dev_priv->pm_irq_mask;
@@@ -296,6 -292,23 +296,23 @@@ void gen6_enable_rps_interrupts(struct 
        spin_unlock_irq(&dev_priv->irq_lock);
  }
  
+ u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
+ {
+       /*
+        * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
+        * if GEN6_PM_UP_EI_EXPIRED is masked.
+        *
+        * TODO: verify if this can be reproduced on VLV,CHV.
+        */
+       if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
+               mask &= ~GEN6_PM_RP_UP_EI_EXPIRED;
+       if (INTEL_INFO(dev_priv)->gen >= 8)
+               mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+       return mask;
+ }
  void gen6_disable_rps_interrupts(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
        spin_lock_irq(&dev_priv->irq_lock);
  
-       I915_WRITE(GEN6_PMINTRMSK, INTEL_INFO(dev_priv)->gen >= 8 ?
-                  ~GEN8_PMINTR_REDIRECT_TO_NON_DISP : ~0);
+       I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
  
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
@@@ -336,8 -348,6 +352,8 @@@ void ibx_display_interrupt_update(struc
        sdeimr &= ~interrupt_mask;
        sdeimr |= (~enabled_irq_mask & interrupt_mask);
  
 +      WARN_ON(enabled_irq_mask & ~interrupt_mask);
 +
        assert_spin_locked(&dev_priv->irq_lock);
  
        if (WARN_ON(!intel_irqs_enabled(dev_priv)))
@@@ -1023,7 -1033,7 +1039,7 @@@ static void notify_ring(struct drm_devi
        if (!intel_ring_initialized(ring))
                return;
  
 -      trace_i915_gem_request_complete(ring);
 +      trace_i915_gem_request_notify(ring);
  
        wake_up_all(&ring->irq_queue);
  }
@@@ -1389,14 -1399,14 +1405,14 @@@ static irqreturn_t gen8_gt_irq_handler(
                        if (rcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
 -                              intel_execlists_handle_ctx_events(ring);
 +                              intel_lrc_irq_handler(ring);
  
                        bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
                        ring = &dev_priv->ring[BCS];
                        if (bcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
 -                              intel_execlists_handle_ctx_events(ring);
 +                              intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
 -                              intel_execlists_handle_ctx_events(ring);
 +                              intel_lrc_irq_handler(ring);
  
                        vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
                        ring = &dev_priv->ring[VCS2];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
 -                              intel_execlists_handle_ctx_events(ring);
 +                              intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
                        if (vcs & GT_RENDER_USER_INTERRUPT)
                                notify_ring(dev, ring);
                        if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
 -                              intel_execlists_handle_ctx_events(ring);
 +                              intel_lrc_irq_handler(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@@ -2759,18 -2769,18 +2775,18 @@@ static void gen8_disable_vblank(struct 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
  }
  
 -static u32
 -ring_last_seqno(struct intel_engine_cs *ring)
 +static struct drm_i915_gem_request *
 +ring_last_request(struct intel_engine_cs *ring)
  {
        return list_entry(ring->request_list.prev,
 -                        struct drm_i915_gem_request, list)->seqno;
 +                        struct drm_i915_gem_request, list);
  }
  
  static bool
 -ring_idle(struct intel_engine_cs *ring, u32 seqno)
 +ring_idle(struct intel_engine_cs *ring)
  {
        return (list_empty(&ring->request_list) ||
 -              i915_seqno_passed(seqno, ring_last_seqno(ring)));
 +              i915_gem_request_completed(ring_last_request(ring), false));
  }
  
  static bool
@@@ -2990,7 -3000,7 +3006,7 @@@ static void i915_hangcheck_elapsed(unsi
                acthd = intel_ring_get_active_head(ring);
  
                if (ring->hangcheck.seqno == seqno) {
 -                      if (ring_idle(ring, seqno)) {
 +                      if (ring_idle(ring)) {
                                ring->hangcheck.action = HANGCHECK_IDLE;
  
                                if (waitqueue_active(&ring->irq_queue)) {
@@@ -3731,8 -3741,6 +3747,6 @@@ static bool i8xx_handle_vblank(struct d
        if ((iir & flip_pending) == 0)
                goto check_page_flip;
  
-       intel_prepare_page_flip(dev, plane);
        /* We detect FlipDone by looking for the change in PendingFlip from '1'
         * to '0' on the following vblank, i.e. IIR has the Pendingflip
         * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
        if (I915_READ16(ISR) & flip_pending)
                goto check_page_flip;
  
+       intel_prepare_page_flip(dev, plane);
        intel_finish_page_flip(dev, pipe);
        return true;
  
@@@ -3913,8 -3922,6 +3928,6 @@@ static bool i915_handle_vblank(struct d
        if ((iir & flip_pending) == 0)
                goto check_page_flip;
  
-       intel_prepare_page_flip(dev, plane);
        /* We detect FlipDone by looking for the change in PendingFlip from '1'
         * to '0' on the following vblank, i.e. IIR has the Pendingflip
         * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
        if (I915_READ(ISR) & flip_pending)
                goto check_page_flip;
  
+       intel_prepare_page_flip(dev, plane);
        intel_finish_page_flip(dev, pipe);
        return true;
  
index d01db1b8286984fb87210b96eb95f387324025ff,e7a16f119a294d0d20d0afa832d6d0b2a803edd7..dc266e772340f4c397d7b39a1522cc5fa171869b
@@@ -1024,7 -1024,7 +1024,7 @@@ void assert_pll(struct drm_i915_privat
        reg = DPLL(pipe);
        val = I915_READ(reg);
        cur_state = !!(val & DPLL_VCO_ENABLE);
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "PLL state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
  }
@@@ -1040,7 -1040,7 +1040,7 @@@ static void assert_dsi_pll(struct drm_i
        mutex_unlock(&dev_priv->dpio_lock);
  
        cur_state = val & DSI_PLL_VCO_EN;
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "DSI PLL state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
  }
@@@ -1071,7 -1071,7 +1071,7 @@@ void assert_shared_dpll(struct drm_i915
                return;
  
        cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "%s assertion failure (expected %s, current %s)\n",
             pll->name, state_string(state), state_string(cur_state));
  }
@@@ -1095,7 -1095,7 +1095,7 @@@ static void assert_fdi_tx(struct drm_i9
                val = I915_READ(reg);
                cur_state = !!(val & FDI_TX_ENABLE);
        }
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "FDI TX state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
  }
@@@ -1112,7 -1112,7 +1112,7 @@@ static void assert_fdi_rx(struct drm_i9
        reg = FDI_RX_CTL(pipe);
        val = I915_READ(reg);
        cur_state = !!(val & FDI_RX_ENABLE);
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "FDI RX state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
  }
@@@ -1135,7 -1135,7 +1135,7 @@@ static void assert_fdi_tx_pll_enabled(s
  
        reg = FDI_TX_CTL(pipe);
        val = I915_READ(reg);
 -      WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
 +      I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
  }
  
  void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
        reg = FDI_RX_CTL(pipe);
        val = I915_READ(reg);
        cur_state = !!(val & FDI_RX_PLL_ENABLE);
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "FDI RX PLL assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
  }
@@@ -1190,7 -1190,7 +1190,7 @@@ void assert_panel_unlocked(struct drm_i
            ((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
                locked = false;
  
 -      WARN(panel_pipe == pipe && locked,
 +      I915_STATE_WARN(panel_pipe == pipe && locked,
             "panel assertion failure, pipe %c regs locked\n",
             pipe_name(pipe));
  }
@@@ -1206,7 -1206,7 +1206,7 @@@ static void assert_cursor(struct drm_i9
        else
                cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
  
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "cursor on pipe %c assertion failure (expected %s, current %s)\n",
             pipe_name(pipe), state_string(state), state_string(cur_state));
  }
@@@ -1236,7 -1236,7 +1236,7 @@@ void assert_pipe(struct drm_i915_privat
                cur_state = !!(val & PIPECONF_ENABLE);
        }
  
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "pipe %c assertion failure (expected %s, current %s)\n",
             pipe_name(pipe), state_string(state), state_string(cur_state));
  }
@@@ -1251,7 -1251,7 +1251,7 @@@ static void assert_plane(struct drm_i91
        reg = DSPCNTR(plane);
        val = I915_READ(reg);
        cur_state = !!(val & DISPLAY_PLANE_ENABLE);
 -      WARN(cur_state != state,
 +      I915_STATE_WARN(cur_state != state,
             "plane %c assertion failure (expected %s, current %s)\n",
             plane_name(plane), state_string(state), state_string(cur_state));
  }
@@@ -1271,7 -1271,7 +1271,7 @@@ static void assert_planes_disabled(stru
        if (INTEL_INFO(dev)->gen >= 4) {
                reg = DSPCNTR(pipe);
                val = I915_READ(reg);
 -              WARN(val & DISPLAY_PLANE_ENABLE,
 +              I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE,
                     "plane %c assertion failure, should be disabled but not\n",
                     plane_name(pipe));
                return;
                val = I915_READ(reg);
                cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
                        DISPPLANE_SEL_PIPE_SHIFT;
 -              WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
 +              I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
                     "plane %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(i), pipe_name(pipe));
        }
@@@ -1299,7 -1299,7 +1299,7 @@@ static void assert_sprites_disabled(str
        if (INTEL_INFO(dev)->gen >= 9) {
                for_each_sprite(pipe, sprite) {
                        val = I915_READ(PLANE_CTL(pipe, sprite));
 -                      WARN(val & PLANE_CTL_ENABLE,
 +                      I915_STATE_WARN(val & PLANE_CTL_ENABLE,
                             "plane %d assertion failure, should be off on pipe %c but is still active\n",
                             sprite, pipe_name(pipe));
                }
                for_each_sprite(pipe, sprite) {
                        reg = SPCNTR(pipe, sprite);
                        val = I915_READ(reg);
 -                      WARN(val & SP_ENABLE,
 +                      I915_STATE_WARN(val & SP_ENABLE,
                             "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                             sprite_name(pipe, sprite), pipe_name(pipe));
                }
        } else if (INTEL_INFO(dev)->gen >= 7) {
                reg = SPRCTL(pipe);
                val = I915_READ(reg);
 -              WARN(val & SPRITE_ENABLE,
 +              I915_STATE_WARN(val & SPRITE_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(pipe), pipe_name(pipe));
        } else if (INTEL_INFO(dev)->gen >= 5) {
                reg = DVSCNTR(pipe);
                val = I915_READ(reg);
 -              WARN(val & DVS_ENABLE,
 +              I915_STATE_WARN(val & DVS_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(pipe), pipe_name(pipe));
        }
  
  static void assert_vblank_disabled(struct drm_crtc *crtc)
  {
 -      if (WARN_ON(drm_crtc_vblank_get(crtc) == 0))
 +      if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
                drm_crtc_vblank_put(crtc);
  }
  
@@@ -1337,12 -1337,12 +1337,12 @@@ static void ibx_assert_pch_refclk_enabl
        u32 val;
        bool enabled;
  
 -      WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
 +      I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
  
        val = I915_READ(PCH_DREF_CONTROL);
        enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
                            DREF_SUPERSPREAD_SOURCE_MASK));
 -      WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
 +      I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
  }
  
  static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
        reg = PCH_TRANSCONF(pipe);
        val = I915_READ(reg);
        enabled = !!(val & TRANS_ENABLE);
 -      WARN(enabled,
 +      I915_STATE_WARN(enabled,
             "transcoder assertion failed, should be off on pipe %c but is still active\n",
             pipe_name(pipe));
  }
@@@ -1435,11 -1435,11 +1435,11 @@@ static void assert_pch_dp_disabled(stru
                                   enum pipe pipe, int reg, u32 port_sel)
  {
        u32 val = I915_READ(reg);
 -      WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
 +      I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
             "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
  
 -      WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
 +      I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
             && (val & DP_PIPEB_SELECT),
             "IBX PCH dp port still using transcoder B\n");
  }
@@@ -1448,11 -1448,11 +1448,11 @@@ static void assert_pch_hdmi_disabled(st
                                     enum pipe pipe, int reg)
  {
        u32 val = I915_READ(reg);
 -      WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
 +      I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
             "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
             reg, pipe_name(pipe));
  
 -      WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
 +      I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
             && (val & SDVO_PIPE_B_SELECT),
             "IBX PCH hdmi port still using transcoder B\n");
  }
@@@ -1469,13 -1469,13 +1469,13 @@@ static void assert_pch_ports_disabled(s
  
        reg = PCH_ADPA;
        val = I915_READ(reg);
 -      WARN(adpa_pipe_enabled(dev_priv, pipe, val),
 +      I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val),
             "PCH VGA enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
  
        reg = PCH_LVDS;
        val = I915_READ(reg);
 -      WARN(lvds_pipe_enabled(dev_priv, pipe, val),
 +      I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val),
             "PCH LVDS enabled on transcoder %c, should be disabled\n",
             pipe_name(pipe));
  
@@@ -2954,6 -2954,71 +2954,6 @@@ static void intel_update_pipe_size(stru
        crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
  }
  
 -static int
 -intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 -                  struct drm_framebuffer *fb)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      enum pipe pipe = intel_crtc->pipe;
 -      struct drm_framebuffer *old_fb = crtc->primary->fb;
 -      struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
 -      int ret;
 -
 -      if (intel_crtc_has_pending_flip(crtc)) {
 -              DRM_ERROR("pipe is still busy with an old pageflip\n");
 -              return -EBUSY;
 -      }
 -
 -      /* no fb bound */
 -      if (!fb) {
 -              DRM_ERROR("No FB bound\n");
 -              return 0;
 -      }
 -
 -      if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
 -              DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n",
 -                        plane_name(intel_crtc->plane),
 -                        INTEL_INFO(dev)->num_pipes);
 -              return -EINVAL;
 -      }
 -
 -      mutex_lock(&dev->struct_mutex);
 -      ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
 -      if (ret == 0)
 -              i915_gem_track_fb(old_obj, intel_fb_obj(fb),
 -                                INTEL_FRONTBUFFER_PRIMARY(pipe));
 -      mutex_unlock(&dev->struct_mutex);
 -      if (ret != 0) {
 -              DRM_ERROR("pin & fence failed\n");
 -              return ret;
 -      }
 -
 -      dev_priv->display.update_primary_plane(crtc, fb, x, y);
 -
 -      if (intel_crtc->active)
 -              intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
 -
 -      crtc->primary->fb = fb;
 -      crtc->x = x;
 -      crtc->y = y;
 -
 -      if (old_fb) {
 -              if (intel_crtc->active && old_fb != fb)
 -                      intel_wait_for_vblank(dev, intel_crtc->pipe);
 -              mutex_lock(&dev->struct_mutex);
 -              intel_unpin_fb_obj(old_obj);
 -              mutex_unlock(&dev->struct_mutex);
 -      }
 -
 -      mutex_lock(&dev->struct_mutex);
 -      intel_update_fbc(dev);
 -      mutex_unlock(&dev->struct_mutex);
 -
 -      return 0;
 -}
 -
  static void intel_fdi_normal_train(struct drm_crtc *crtc)
  {
        struct drm_device *dev = crtc->dev;
@@@ -4060,7 -4125,7 +4060,7 @@@ static void intel_disable_planes(struc
        drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                intel_plane = to_intel_plane(plane);
                if (intel_plane->pipe == pipe)
 -                      intel_plane_disable(&intel_plane->base);
 +                      plane->funcs->disable_plane(plane);
        }
  }
  
@@@ -4201,7 -4266,7 +4201,7 @@@ static void intel_crtc_enable_planes(st
        hsw_enable_ips(intel_crtc);
  
        mutex_lock(&dev->struct_mutex);
 -      intel_update_fbc(dev);
 +      intel_fbc_update(dev);
        mutex_unlock(&dev->struct_mutex);
  
        /*
@@@ -4223,7 -4288,7 +4223,7 @@@ static void intel_crtc_disable_planes(s
        intel_crtc_wait_for_pending_flips(crtc);
  
        if (dev_priv->fbc.plane == plane)
 -              intel_disable_fbc(dev);
 +              intel_fbc_disable(dev);
  
        hsw_disable_ips(intel_crtc);
  
@@@ -4526,7 -4591,7 +4526,7 @@@ static void ironlake_crtc_disable(struc
        intel_update_watermarks(crtc);
  
        mutex_lock(&dev->struct_mutex);
 -      intel_update_fbc(dev);
 +      intel_fbc_update(dev);
        mutex_unlock(&dev->struct_mutex);
  }
  
@@@ -4581,7 -4646,7 +4581,7 @@@ static void haswell_crtc_disable(struc
        intel_update_watermarks(crtc);
  
        mutex_lock(&dev->struct_mutex);
 -      intel_update_fbc(dev);
 +      intel_fbc_update(dev);
        mutex_unlock(&dev->struct_mutex);
  
        if (intel_crtc_to_shared_dpll(intel_crtc))
@@@ -4844,7 -4909,7 +4844,7 @@@ static void cherryview_set_cdclk(struc
                cmd = 0;
                break;
        default:
 -              WARN_ON(1);
 +              MISSING_CASE(cdclk);
                return;
        }
  
@@@ -5186,7 -5251,7 +5186,7 @@@ static void i9xx_crtc_disable(struct dr
        intel_update_watermarks(crtc);
  
        mutex_lock(&dev->struct_mutex);
 -      intel_update_fbc(dev);
 +      intel_fbc_update(dev);
        mutex_unlock(&dev->struct_mutex);
  }
  
@@@ -5244,6 -5309,8 +5244,6 @@@ static void intel_crtc_disable(struct d
        struct drm_device *dev = crtc->dev;
        struct drm_connector *connector;
        struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_i915_gem_object *old_obj = intel_fb_obj(crtc->primary->fb);
 -      enum pipe pipe = to_intel_crtc(crtc)->pipe;
  
        /* crtc should still be enabled when we disable it. */
        WARN_ON(!crtc->enabled);
        dev_priv->display.crtc_disable(crtc);
        dev_priv->display.off(crtc);
  
 -      if (crtc->primary->fb) {
 -              mutex_lock(&dev->struct_mutex);
 -              intel_unpin_fb_obj(old_obj);
 -              i915_gem_track_fb(old_obj, NULL,
 -                                INTEL_FRONTBUFFER_PRIMARY(pipe));
 -              mutex_unlock(&dev->struct_mutex);
 -              crtc->primary->fb = NULL;
 -      }
 +      crtc->primary->funcs->disable_plane(crtc->primary);
  
        /* Update computed state. */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@@ -5308,25 -5382,25 +5308,25 @@@ static void intel_connector_check_state
                if (connector->mst_port)
                        return;
  
 -              WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
 +              I915_STATE_WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
                     "wrong connector dpms state\n");
 -              WARN(connector->base.encoder != &encoder->base,
 +              I915_STATE_WARN(connector->base.encoder != &encoder->base,
                     "active connector not linked to encoder\n");
  
                if (encoder) {
 -                      WARN(!encoder->connectors_active,
 +                      I915_STATE_WARN(!encoder->connectors_active,
                             "encoder->connectors_active not set\n");
  
                        encoder_enabled = encoder->get_hw_state(encoder, &pipe);
 -                      WARN(!encoder_enabled, "encoder not enabled\n");
 -                      if (WARN_ON(!encoder->base.crtc))
 +                      I915_STATE_WARN(!encoder_enabled, "encoder not enabled\n");
 +                      if (I915_STATE_WARN_ON(!encoder->base.crtc))
                                return;
  
                        crtc = encoder->base.crtc;
  
 -                      WARN(!crtc->enabled, "crtc not enabled\n");
 -                      WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
 -                      WARN(pipe != to_intel_crtc(crtc)->pipe,
 +                      I915_STATE_WARN(!crtc->enabled, "crtc not enabled\n");
 +                      I915_STATE_WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
 +                      I915_STATE_WARN(pipe != to_intel_crtc(crtc)->pipe,
                             "encoder active on the wrong pipe\n");
                }
        }
@@@ -7736,24 -7810,24 +7736,24 @@@ static void assert_can_disable_lcpll(st
        struct intel_crtc *crtc;
  
        for_each_intel_crtc(dev, crtc)
 -              WARN(crtc->active, "CRTC for pipe %c enabled\n",
 +              I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
                     pipe_name(crtc->pipe));
  
 -      WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
 -      WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
 -      WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
 -      WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
 -      WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
 -      WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
 +      I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
 +      I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
 +      I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
 +      I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
 +      I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
 +      I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
             "CPU PWM1 enabled\n");
        if (IS_HASWELL(dev))
 -              WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
 +              I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
                     "CPU PWM2 enabled\n");
 -      WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
 +      I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
             "PCH PWM1 enabled\n");
 -      WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
 +      I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
             "Utility pin enabled\n");
 -      WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
 +      I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
  
        /*
         * In theory we can still leave IRQs enabled, as long as only the HPD
         * gen-specific and since we only disable LCPLL after we fully disable
         * the interrupts, the check below should be enough.
         */
 -      WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
 +      I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
  }
  
  static uint32_t hsw_read_dcomp(struct drm_i915_private *dev_priv)
@@@ -7981,21 -8055,12 +7981,21 @@@ static void skylake_get_ddi_pll(struct 
                                enum port port,
                                struct intel_crtc_config *pipe_config)
  {
 -      u32 temp;
 +      u32 temp, dpll_ctl1;
  
        temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
        pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
  
        switch (pipe_config->ddi_pll_sel) {
 +      case SKL_DPLL0:
 +              /*
 +               * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
 +               * of the shared DPLL framework and thus needs to be read out
 +               * separately
 +               */
 +              dpll_ctl1 = I915_READ(DPLL_CTRL1);
 +              pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
 +              break;
        case SKL_DPLL1:
                pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
                break;
@@@ -8221,7 -8286,7 +8221,7 @@@ static void i9xx_update_cursor(struct d
                                cntl |= CURSOR_MODE_256_ARGB_AX;
                                break;
                        default:
 -                              WARN_ON(1);
 +                              MISSING_CASE(intel_crtc->cursor_width);
                                return;
                }
                cntl |= pipe << 28; /* Connect to correct pipe */
@@@ -8340,6 -8405,109 +8340,6 @@@ static bool cursor_size_ok(struct drm_d
        return true;
  }
  
 -static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
 -                                   struct drm_i915_gem_object *obj,
 -                                   uint32_t width, uint32_t height)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = to_i915(dev);
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      enum pipe pipe = intel_crtc->pipe;
 -      unsigned old_width;
 -      uint32_t addr;
 -      int ret;
 -
 -      /* if we want to turn off the cursor ignore width and height */
 -      if (!obj) {
 -              DRM_DEBUG_KMS("cursor off\n");
 -              addr = 0;
 -              mutex_lock(&dev->struct_mutex);
 -              goto finish;
 -      }
 -
 -      /* we only need to pin inside GTT if cursor is non-phy */
 -      mutex_lock(&dev->struct_mutex);
 -      if (!INTEL_INFO(dev)->cursor_needs_physical) {
 -              unsigned alignment;
 -
 -              /*
 -               * Global gtt pte registers are special registers which actually
 -               * forward writes to a chunk of system memory. Which means that
 -               * there is no risk that the register values disappear as soon
 -               * as we call intel_runtime_pm_put(), so it is correct to wrap
 -               * only the pin/unpin/fence and not more.
 -               */
 -              intel_runtime_pm_get(dev_priv);
 -
 -              /* Note that the w/a also requires 2 PTE of padding following
 -               * the bo. We currently fill all unused PTE with the shadow
 -               * page and so we should always have valid PTE following the
 -               * cursor preventing the VT-d warning.
 -               */
 -              alignment = 0;
 -              if (need_vtd_wa(dev))
 -                      alignment = 64*1024;
 -
 -              ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
 -              if (ret) {
 -                      DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n");
 -                      intel_runtime_pm_put(dev_priv);
 -                      goto fail_locked;
 -              }
 -
 -              ret = i915_gem_object_put_fence(obj);
 -              if (ret) {
 -                      DRM_DEBUG_KMS("failed to release fence for cursor");
 -                      intel_runtime_pm_put(dev_priv);
 -                      goto fail_unpin;
 -              }
 -
 -              addr = i915_gem_obj_ggtt_offset(obj);
 -
 -              intel_runtime_pm_put(dev_priv);
 -      } else {
 -              int align = IS_I830(dev) ? 16 * 1024 : 256;
 -              ret = i915_gem_object_attach_phys(obj, align);
 -              if (ret) {
 -                      DRM_DEBUG_KMS("failed to attach phys object\n");
 -                      goto fail_locked;
 -              }
 -              addr = obj->phys_handle->busaddr;
 -      }
 -
 - finish:
 -      if (intel_crtc->cursor_bo) {
 -              if (!INTEL_INFO(dev)->cursor_needs_physical)
 -                      i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo);
 -      }
 -
 -      i915_gem_track_fb(intel_crtc->cursor_bo, obj,
 -                        INTEL_FRONTBUFFER_CURSOR(pipe));
 -      mutex_unlock(&dev->struct_mutex);
 -
 -      old_width = intel_crtc->cursor_width;
 -
 -      intel_crtc->cursor_addr = addr;
 -      intel_crtc->cursor_bo = obj;
 -      intel_crtc->cursor_width = width;
 -      intel_crtc->cursor_height = height;
 -
 -      if (intel_crtc->active) {
 -              if (old_width != width)
 -                      intel_update_watermarks(crtc);
 -              intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
 -
 -              intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
 -      }
 -
 -      return 0;
 -fail_unpin:
 -      i915_gem_object_unpin_from_display_plane(obj);
 -fail_locked:
 -      mutex_unlock(&dev->struct_mutex);
 -      return ret;
 -}
 -
  static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
                                 u16 *blue, uint32_t start, uint32_t size)
  {
@@@ -8947,10 -9115,7 +8947,10 @@@ static void intel_unpin_work_fn(struct 
        drm_gem_object_unreference(&work->pending_flip_obj->base);
        drm_gem_object_unreference(&work->old_fb_obj->base);
  
 -      intel_update_fbc(dev);
 +      intel_fbc_update(dev);
 +
 +      if (work->flip_queued_req)
 +              i915_gem_request_assign(&work->flip_queued_req, NULL);
        mutex_unlock(&dev->struct_mutex);
  
        intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
@@@ -9346,53 -9511,25 +9346,53 @@@ static bool use_mmio_flip(struct intel_
        else if (i915.enable_execlists)
                return true;
        else
 -              return ring != obj->ring;
 +              return ring != i915_gem_request_get_ring(obj->last_read_req);
  }
  
 -static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
 +static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
 +{
 +      struct drm_device *dev = intel_crtc->base.dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
 +      struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 +      struct drm_i915_gem_object *obj = intel_fb->obj;
 +      const enum pipe pipe = intel_crtc->pipe;
 +      u32 ctl, stride;
 +
 +      ctl = I915_READ(PLANE_CTL(pipe, 0));
 +      ctl &= ~PLANE_CTL_TILED_MASK;
 +      if (obj->tiling_mode == I915_TILING_X)
 +              ctl |= PLANE_CTL_TILED_X;
 +
 +      /*
 +       * The stride is either expressed as a multiple of 64 bytes chunks for
 +       * linear buffers or in number of tiles for tiled buffers.
 +       */
 +      stride = fb->pitches[0] >> 6;
 +      if (obj->tiling_mode == I915_TILING_X)
 +              stride = fb->pitches[0] >> 9; /* X tiles are 512 bytes wide */
 +
 +      /*
 +       * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
 +       * PLANE_SURF updates, the update is then guaranteed to be atomic.
 +       */
 +      I915_WRITE(PLANE_CTL(pipe, 0), ctl);
 +      I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
 +
 +      I915_WRITE(PLANE_SURF(pipe, 0), intel_crtc->unpin_work->gtt_offset);
 +      POSTING_READ(PLANE_SURF(pipe, 0));
 +}
 +
 +static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
  {
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_framebuffer *intel_fb =
                to_intel_framebuffer(intel_crtc->base.primary->fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
 -      bool atomic_update;
 -      u32 start_vbl_count;
        u32 dspcntr;
        u32 reg;
  
 -      intel_mark_page_flip_active(intel_crtc);
 -
 -      atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 -
        reg = DSPCNTR(intel_crtc->plane);
        dspcntr = I915_READ(reg);
  
                   intel_crtc->unpin_work->gtt_offset);
        POSTING_READ(DSPSURF(intel_crtc->plane));
  
 +}
 +
 +/*
 + * XXX: This is the temporary way to update the plane registers until we get
 + * around to using the usual plane update functions for MMIO flips
 + */
 +static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
 +{
 +      struct drm_device *dev = intel_crtc->base.dev;
 +      bool atomic_update;
 +      u32 start_vbl_count;
 +
 +      intel_mark_page_flip_active(intel_crtc);
 +
 +      atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
 +
 +      if (INTEL_INFO(dev)->gen >= 9)
 +              skl_do_mmio_flip(intel_crtc);
 +      else
 +              /* use_mmio_flip() retricts MMIO flips to ilk+ */
 +              ilk_do_mmio_flip(intel_crtc);
 +
        if (atomic_update)
                intel_pipe_update_end(intel_crtc, start_vbl_count);
  }
  
  static void intel_mmio_flip_work_func(struct work_struct *work)
  {
 -      struct intel_crtc *intel_crtc =
 +      struct intel_crtc *crtc =
                container_of(work, struct intel_crtc, mmio_flip.work);
 -      struct intel_engine_cs *ring;
 -      uint32_t seqno;
 -
 -      seqno = intel_crtc->mmio_flip.seqno;
 -      ring = intel_crtc->mmio_flip.ring;
 +      struct intel_mmio_flip *mmio_flip;
  
 -      if (seqno)
 -              WARN_ON(__i915_wait_seqno(ring, seqno,
 -                                        intel_crtc->reset_counter,
 -                                        false, NULL, NULL) != 0);
 +      mmio_flip = &crtc->mmio_flip;
 +      if (mmio_flip->req)
 +              WARN_ON(__i915_wait_request(mmio_flip->req,
 +                                          crtc->reset_counter,
 +                                          false, NULL, NULL) != 0);
  
 -      intel_do_mmio_flip(intel_crtc);
 +      intel_do_mmio_flip(crtc);
 +      if (mmio_flip->req) {
 +              mutex_lock(&crtc->base.dev->struct_mutex);
 +              i915_gem_request_assign(&mmio_flip->req, NULL);
 +              mutex_unlock(&crtc->base.dev->struct_mutex);
 +      }
  }
  
  static int intel_queue_mmio_flip(struct drm_device *dev,
  {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
  
 -      intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
 -      intel_crtc->mmio_flip.ring = obj->ring;
 +      i915_gem_request_assign(&intel_crtc->mmio_flip.req,
 +                              obj->last_write_req);
  
        schedule_work(&intel_crtc->mmio_flip.work);
  
@@@ -9558,8 -9671,9 +9558,8 @@@ static bool __intel_pageflip_stall_chec
                return false;
  
        if (work->flip_ready_vblank == 0) {
 -              if (work->flip_queued_ring &&
 -                  !i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
 -                                     work->flip_queued_seqno))
 +              if (work->flip_queued_req &&
 +                  !i915_gem_request_completed(work->flip_queued_req, true))
                        return false;
  
                work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
@@@ -9612,8 -9726,6 +9612,8 @@@ static int intel_crtc_page_flip(struct 
        struct drm_framebuffer *old_fb = crtc->primary->fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 +      struct drm_plane *primary = crtc->primary;
 +      struct intel_plane *intel_plane = to_intel_plane(primary);
        enum pipe pipe = intel_crtc->pipe;
        struct intel_unpin_work *work;
        struct intel_engine_cs *ring;
                if (obj->tiling_mode != work->old_fb_obj->tiling_mode)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        ring = NULL;
-       } else if (IS_IVYBRIDGE(dev)) {
+       } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                ring = &dev_priv->ring[BCS];
        } else if (INTEL_INFO(dev)->gen >= 7) {
 -              ring = obj->ring;
 +              ring = i915_gem_request_get_ring(obj->last_read_req);
                if (ring == NULL || ring->id != RCS)
                        ring = &dev_priv->ring[BCS];
        } else {
                if (ret)
                        goto cleanup_unpin;
  
 -              work->flip_queued_seqno = obj->last_write_seqno;
 -              work->flip_queued_ring = obj->ring;
 +              i915_gem_request_assign(&work->flip_queued_req,
 +                                      obj->last_write_req);
        } else {
                ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
                                                   page_flip_flags);
                if (ret)
                        goto cleanup_unpin;
  
 -              work->flip_queued_seqno = intel_ring_get_seqno(ring);
 -              work->flip_queued_ring = ring;
 +              i915_gem_request_assign(&work->flip_queued_req,
 +                                      intel_ring_get_request(ring));
        }
  
        work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
        i915_gem_track_fb(work->old_fb_obj, obj,
                          INTEL_FRONTBUFFER_PRIMARY(pipe));
  
 -      intel_disable_fbc(dev);
 +      intel_fbc_disable(dev);
        intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
        mutex_unlock(&dev->struct_mutex);
  
@@@ -9772,15 -9884,8 +9772,15 @@@ free_work
  
        if (ret == -EIO) {
  out_hang:
 -              intel_crtc_wait_for_pending_flips(crtc);
 -              ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb);
 +              ret = primary->funcs->update_plane(primary, crtc, fb,
 +                                                 intel_plane->crtc_x,
 +                                                 intel_plane->crtc_y,
 +                                                 intel_plane->crtc_h,
 +                                                 intel_plane->crtc_w,
 +                                                 intel_plane->src_x,
 +                                                 intel_plane->src_y,
 +                                                 intel_plane->src_h,
 +                                                 intel_plane->src_w);
                if (ret == 0 && event) {
                        spin_lock_irq(&dev->event_lock);
                        drm_send_vblank_event(dev, pipe, event);
@@@ -10149,9 -10254,9 +10149,9 @@@ intel_modeset_pipe_config(struct drm_cr
         * computation to clearly distinguish it from the adjusted mode, which
         * can be changed by the connectors in the below retry loop.
         */
 -      drm_mode_set_crtcinfo(&pipe_config->requested_mode, CRTC_STEREO_DOUBLE);
 -      pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay;
 -      pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay;
 +      drm_crtc_get_hv_timing(&pipe_config->requested_mode,
 +                             &pipe_config->pipe_src_w,
 +                             &pipe_config->pipe_src_h);
  
  encoder_retry:
        /* Ensure the port clock defaults are reset when retrying. */
@@@ -10637,7 -10742,7 +10637,7 @@@ check_connector_state(struct drm_devic
                 * ->get_hw_state callbacks. */
                intel_connector_check_state(connector);
  
 -              WARN(&connector->new_encoder->base != connector->base.encoder,
 +              I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder,
                     "connector's staged encoder doesn't match current encoder\n");
        }
  }
@@@ -10657,9 -10762,9 +10657,9 @@@ check_encoder_state(struct drm_device *
                              encoder->base.base.id,
                              encoder->base.name);
  
 -              WARN(&encoder->new_crtc->base != encoder->base.crtc,
 +              I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc,
                     "encoder's stage crtc doesn't match current crtc\n");
 -              WARN(encoder->connectors_active && !encoder->base.crtc,
 +              I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
                     "encoder's active_connectors set, but no crtc\n");
  
                list_for_each_entry(connector, &dev->mode_config.connector_list,
                if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
                        continue;
  
 -              WARN(!!encoder->base.crtc != enabled,
 +              I915_STATE_WARN(!!encoder->base.crtc != enabled,
                     "encoder's enabled state mismatch "
                     "(expected %i, found %i)\n",
                     !!encoder->base.crtc, enabled);
 -              WARN(active && !encoder->base.crtc,
 +              I915_STATE_WARN(active && !encoder->base.crtc,
                     "active encoder with no crtc\n");
  
 -              WARN(encoder->connectors_active != active,
 +              I915_STATE_WARN(encoder->connectors_active != active,
                     "encoder's computed active state doesn't match tracked active state "
                     "(expected %i, found %i)\n", active, encoder->connectors_active);
  
                active = encoder->get_hw_state(encoder, &pipe);
 -              WARN(active != encoder->connectors_active,
 +              I915_STATE_WARN(active != encoder->connectors_active,
                     "encoder's hw state doesn't match sw tracking "
                     "(expected %i, found %i)\n",
                     encoder->connectors_active, active);
                        continue;
  
                tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
 -              WARN(active && pipe != tracked_pipe,
 +              I915_STATE_WARN(active && pipe != tracked_pipe,
                     "active encoder's pipe doesn't match"
                     "(expected %i, found %i)\n",
                     tracked_pipe, pipe);
@@@ -10724,7 -10829,7 +10724,7 @@@ check_crtc_state(struct drm_device *dev
                DRM_DEBUG_KMS("[CRTC:%d]\n",
                              crtc->base.base.id);
  
 -              WARN(crtc->active && !crtc->base.enabled,
 +              I915_STATE_WARN(crtc->active && !crtc->base.enabled,
                     "active crtc, but not enabled in sw tracking\n");
  
                for_each_intel_encoder(dev, encoder) {
                                active = true;
                }
  
 -              WARN(active != crtc->active,
 +              I915_STATE_WARN(active != crtc->active,
                     "crtc's computed active state doesn't match tracked active state "
                     "(expected %i, found %i)\n", active, crtc->active);
 -              WARN(enabled != crtc->base.enabled,
 +              I915_STATE_WARN(enabled != crtc->base.enabled,
                     "crtc's computed enabled state doesn't match tracked enabled state "
                     "(expected %i, found %i)\n", enabled, crtc->base.enabled);
  
                                encoder->get_config(encoder, &pipe_config);
                }
  
 -              WARN(crtc->active != active,
 +              I915_STATE_WARN(crtc->active != active,
                     "crtc active state doesn't match with hw state "
                     "(expected %i, found %i)\n", crtc->active, active);
  
                if (active &&
                    !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) {
 -                      WARN(1, "pipe state doesn't match!\n");
 +                      I915_STATE_WARN(1, "pipe state doesn't match!\n");
                        intel_dump_pipe_config(crtc, &pipe_config,
                                               "[hw state]");
                        intel_dump_pipe_config(crtc, &crtc->config,
@@@ -10792,14 -10897,14 +10792,14 @@@ check_shared_dpll_state(struct drm_devi
  
                active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
  
 -              WARN(pll->active > hweight32(pll->config.crtc_mask),
 +              I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask),
                     "more active pll users than references: %i vs %i\n",
                     pll->active, hweight32(pll->config.crtc_mask));
 -              WARN(pll->active && !pll->on,
 +              I915_STATE_WARN(pll->active && !pll->on,
                     "pll in active use but not on in sw tracking\n");
 -              WARN(pll->on && !pll->active,
 +              I915_STATE_WARN(pll->on && !pll->active,
                     "pll in on but not on in use in sw tracking\n");
 -              WARN(pll->on != active,
 +              I915_STATE_WARN(pll->on != active,
                     "pll on state mismatch (expected %i, found %i)\n",
                     pll->on, active);
  
                        if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
                                active_crtcs++;
                }
 -              WARN(pll->active != active_crtcs,
 +              I915_STATE_WARN(pll->active != active_crtcs,
                     "pll active crtcs mismatch (expected %i, found %i)\n",
                     pll->active, active_crtcs);
 -              WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
 +              I915_STATE_WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
                     "pll enabled crtcs mismatch (expected %i, found %i)\n",
                     hweight32(pll->config.crtc_mask), enabled_crtcs);
  
 -              WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
 +              I915_STATE_WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
                                       sizeof(dpll_hw_state)),
                     "pll hw state mismatch\n");
        }
@@@ -11009,15 -11114,26 +11009,15 @@@ static int __intel_set_mode(struct drm_
         * on the DPLL.
         */
        for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
 -              struct drm_framebuffer *old_fb = crtc->primary->fb;
 -              struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
 -              struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 +              struct drm_plane *primary = intel_crtc->base.primary;
 +              int vdisplay, hdisplay;
  
 -              mutex_lock(&dev->struct_mutex);
 -              ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
 -              if (ret != 0) {
 -                      DRM_ERROR("pin & fence failed\n");
 -                      mutex_unlock(&dev->struct_mutex);
 -                      goto done;
 -              }
 -              if (old_fb)
 -                      intel_unpin_fb_obj(old_obj);
 -              i915_gem_track_fb(old_obj, obj,
 -                                INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
 -              mutex_unlock(&dev->struct_mutex);
 -
 -              crtc->primary->fb = fb;
 -              crtc->x = x;
 -              crtc->y = y;
 +              drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
 +              ret = primary->funcs->update_plane(primary, &intel_crtc->base,
 +                                                 fb, 0, 0,
 +                                                 hdisplay, vdisplay,
 +                                                 x << 16, y << 16,
 +                                                 hdisplay << 16, vdisplay << 16);
        }
  
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@@ -11485,14 -11601,11 +11485,14 @@@ static int intel_crtc_set_config(struc
                                           disable_pipes);
        } else if (config->fb_changed) {
                struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
 +              struct drm_plane *primary = set->crtc->primary;
 +              int vdisplay, hdisplay;
  
 -              intel_crtc_wait_for_pending_flips(set->crtc);
 -
 -              ret = intel_pipe_set_base(set->crtc,
 -                                        set->x, set->y, set->fb);
 +              drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
 +              ret = primary->funcs->update_plane(primary, set->crtc, set->fb,
 +                                                 0, 0, hdisplay, vdisplay,
 +                                                 set->x << 16, set->y << 16,
 +                                                 hdisplay << 16, vdisplay << 16);
  
                /*
                 * We need to make sure the primary plane is re-enabled if it
@@@ -11649,115 -11762,95 +11649,115 @@@ static void intel_shared_dpll_init(stru
        BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
  }
  
 -static int
 -intel_primary_plane_disable(struct drm_plane *plane)
 +/**
 + * intel_prepare_plane_fb - Prepare fb for usage on plane
 + * @plane: drm plane to prepare for
 + * @fb: framebuffer to prepare for presentation
 + *
 + * Prepares a framebuffer for usage on a display plane.  Generally this
 + * involves pinning the underlying object and updating the frontbuffer tracking
 + * bits.  Some older platforms need special physical address handling for
 + * cursor planes.
 + *
 + * Returns 0 on success, negative error code on failure.
 + */
 +int
 +intel_prepare_plane_fb(struct drm_plane *plane,
 +                     struct drm_framebuffer *fb)
  {
        struct drm_device *dev = plane->dev;
 -      struct intel_crtc *intel_crtc;
 +      struct intel_plane *intel_plane = to_intel_plane(plane);
 +      enum pipe pipe = intel_plane->pipe;
 +      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 +      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
 +      unsigned frontbuffer_bits = 0;
 +      int ret = 0;
  
 -      if (!plane->fb)
 +      if (WARN_ON(fb == plane->fb || !obj))
                return 0;
  
 -      BUG_ON(!plane->crtc);
 +      switch (plane->type) {
 +      case DRM_PLANE_TYPE_PRIMARY:
 +              frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe);
 +              break;
 +      case DRM_PLANE_TYPE_CURSOR:
 +              frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe);
 +              break;
 +      case DRM_PLANE_TYPE_OVERLAY:
 +              frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe);
 +              break;
 +      }
  
 -      intel_crtc = to_intel_crtc(plane->crtc);
 +      mutex_lock(&dev->struct_mutex);
  
 -      /*
 -       * Even though we checked plane->fb above, it's still possible that
 -       * the primary plane has been implicitly disabled because the crtc
 -       * coordinates given weren't visible, or because we detected
 -       * that it was 100% covered by a sprite plane.  Or, the CRTC may be
 -       * off and we've set a fb, but haven't actually turned on the CRTC yet.
 -       * In either case, we need to unpin the FB and let the fb pointer get
 -       * updated, but otherwise we don't need to touch the hardware.
 -       */
 -      if (!intel_crtc->primary_enabled)
 -              goto disable_unpin;
 +      if (plane->type == DRM_PLANE_TYPE_CURSOR &&
 +          INTEL_INFO(dev)->cursor_needs_physical) {
 +              int align = IS_I830(dev) ? 16 * 1024 : 256;
 +              ret = i915_gem_object_attach_phys(obj, align);
 +              if (ret)
 +                      DRM_DEBUG_KMS("failed to attach phys object\n");
 +      } else {
 +              ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
 +      }
  
 -      intel_crtc_wait_for_pending_flips(plane->crtc);
 -      intel_disable_primary_hw_plane(plane, plane->crtc);
 +      if (ret == 0)
 +              i915_gem_track_fb(old_obj, obj, frontbuffer_bits);
  
 -disable_unpin:
 -      mutex_lock(&dev->struct_mutex);
 -      i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
 -                        INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
 -      intel_unpin_fb_obj(intel_fb_obj(plane->fb));
        mutex_unlock(&dev->struct_mutex);
 -      plane->fb = NULL;
  
 -      return 0;
 +      return ret;
 +}
 +
 +/**
 + * intel_cleanup_plane_fb - Cleans up an fb after plane use
 + * @plane: drm plane to clean up for
 + * @fb: old framebuffer that was on plane
 + *
 + * Cleans up a framebuffer that has just been removed from a plane.
 + */
 +void
 +intel_cleanup_plane_fb(struct drm_plane *plane,
 +                     struct drm_framebuffer *fb)
 +{
 +      struct drm_device *dev = plane->dev;
 +      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 +
 +      if (WARN_ON(!obj))
 +              return;
 +
 +      if (plane->type != DRM_PLANE_TYPE_CURSOR ||
 +          !INTEL_INFO(dev)->cursor_needs_physical) {
 +              mutex_lock(&dev->struct_mutex);
 +              intel_unpin_fb_obj(obj);
 +              mutex_unlock(&dev->struct_mutex);
 +      }
  }
  
  static int
  intel_check_primary_plane(struct drm_plane *plane,
                          struct intel_plane_state *state)
  {
 -      struct drm_crtc *crtc = state->crtc;
 -      struct drm_framebuffer *fb = state->fb;
 +      struct drm_crtc *crtc = state->base.crtc;
 +      struct drm_framebuffer *fb = state->base.fb;
        struct drm_rect *dest = &state->dst;
        struct drm_rect *src = &state->src;
        const struct drm_rect *clip = &state->clip;
 -
 -      return drm_plane_helper_check_update(plane, crtc, fb,
 -                                           src, dest, clip,
 -                                           DRM_PLANE_HELPER_NO_SCALING,
 -                                           DRM_PLANE_HELPER_NO_SCALING,
 -                                           false, true, &state->visible);
 -}
 -
 -static int
 -intel_prepare_primary_plane(struct drm_plane *plane,
 -                          struct intel_plane_state *state)
 -{
 -      struct drm_crtc *crtc = state->crtc;
 -      struct drm_framebuffer *fb = state->fb;
 -      struct drm_device *dev = crtc->dev;
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      enum pipe pipe = intel_crtc->pipe;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
        int ret;
  
 -      intel_crtc_wait_for_pending_flips(crtc);
 +      ret = drm_plane_helper_check_update(plane, crtc, fb,
 +                                          src, dest, clip,
 +                                          DRM_PLANE_HELPER_NO_SCALING,
 +                                          DRM_PLANE_HELPER_NO_SCALING,
 +                                          false, true, &state->visible);
 +      if (ret)
 +              return ret;
  
 +      intel_crtc_wait_for_pending_flips(crtc);
        if (intel_crtc_has_pending_flip(crtc)) {
                DRM_ERROR("pipe is still busy with an old pageflip\n");
                return -EBUSY;
        }
  
 -      if (old_obj != obj) {
 -              mutex_lock(&dev->struct_mutex);
 -              ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
 -              if (ret == 0)
 -                      i915_gem_track_fb(old_obj, obj,
 -                                        INTEL_FRONTBUFFER_PRIMARY(pipe));
 -              mutex_unlock(&dev->struct_mutex);
 -              if (ret != 0) {
 -                      DRM_DEBUG_KMS("pin & fence failed\n");
 -                      return ret;
 -              }
 -      }
 -
        return 0;
  }
  
@@@ -11765,28 -11858,19 +11765,28 @@@ static voi
  intel_commit_primary_plane(struct drm_plane *plane,
                           struct intel_plane_state *state)
  {
 -      struct drm_crtc *crtc = state->crtc;
 -      struct drm_framebuffer *fb = state->fb;
 -      struct drm_device *dev = crtc->dev;
 +      struct drm_crtc *crtc = state->base.crtc;
 +      struct drm_framebuffer *fb = state->base.fb;
 +      struct drm_device *dev = plane->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      enum pipe pipe = intel_crtc->pipe;
 -      struct drm_framebuffer *old_fb = plane->fb;
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
        struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_rect *src = &state->src;
 +      enum pipe pipe = intel_plane->pipe;
  
 -      crtc->primary->fb = fb;
 +      if (!fb) {
 +              /*
 +               * 'prepare' is never called when plane is being disabled, so
 +               * we need to handle frontbuffer tracking here
 +               */
 +              mutex_lock(&dev->struct_mutex);
 +              i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
 +                                INTEL_FRONTBUFFER_PRIMARY(pipe));
 +              mutex_unlock(&dev->struct_mutex);
 +      }
 +
 +      plane->fb = fb;
        crtc->x = src->x1 >> 16;
        crtc->y = src->y1 >> 16;
  
                    INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
                    dev_priv->fbc.plane == intel_crtc->plane &&
                    intel_plane->rotation != BIT(DRM_ROTATE_0)) {
 -                      intel_disable_fbc(dev);
 +                      intel_fbc_disable(dev);
                }
  
                if (state->visible) {
                intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
  
                mutex_lock(&dev->struct_mutex);
 -              intel_update_fbc(dev);
 -              mutex_unlock(&dev->struct_mutex);
 -      }
 -
 -      if (old_fb && old_fb != fb) {
 -              if (intel_crtc->active)
 -                      intel_wait_for_vblank(dev, intel_crtc->pipe);
 -
 -              mutex_lock(&dev->struct_mutex);
 -              intel_unpin_fb_obj(old_obj);
 +              intel_fbc_update(dev);
                mutex_unlock(&dev->struct_mutex);
        }
  }
  
 -static int
 -intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
 -                           struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 -                           unsigned int crtc_w, unsigned int crtc_h,
 -                           uint32_t src_x, uint32_t src_y,
 -                           uint32_t src_w, uint32_t src_h)
 +int
 +intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 +                 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 +                 unsigned int crtc_w, unsigned int crtc_h,
 +                 uint32_t src_x, uint32_t src_y,
 +                 uint32_t src_w, uint32_t src_h)
  {
 +      struct drm_device *dev = plane->dev;
 +      struct drm_i915_private *dev_priv = dev->dev_private;
 +      struct drm_framebuffer *old_fb = plane->fb;
        struct intel_plane_state state;
 +      struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int ret;
  
 -      state.crtc = crtc;
 -      state.fb = fb;
 +      state.base.crtc = crtc ? crtc : plane->crtc;
 +      state.base.fb = fb;
  
        /* sample coordinates in 16.16 fixed point */
        state.src.x1 = src_x;
        state.orig_src = state.src;
        state.orig_dst = state.dst;
  
 -      ret = intel_check_primary_plane(plane, &state);
 +      ret = intel_plane->check_plane(plane, &state);
        if (ret)
                return ret;
  
 -      ret = intel_prepare_primary_plane(plane, &state);
 -      if (ret)
 -              return ret;
 +      if (fb != old_fb && fb) {
 +              ret = intel_prepare_plane_fb(plane, fb);
 +              if (ret)
 +                      return ret;
 +      }
 +
 +      intel_runtime_pm_get(dev_priv);
 +      intel_plane->commit_plane(plane, &state);
 +      intel_runtime_pm_put(dev_priv);
 +
 +      if (fb != old_fb && old_fb) {
 +              if (intel_crtc->active)
 +                      intel_wait_for_vblank(dev, intel_crtc->pipe);
 +              intel_cleanup_plane_fb(plane, old_fb);
 +      }
  
 -      intel_commit_primary_plane(plane, &state);
 +      plane->fb = fb;
  
        return 0;
  }
  
 +/**
 + * intel_disable_plane - disable a plane
 + * @plane: plane to disable
 + *
 + * General disable handler for all plane types.
 + */
 +int
 +intel_disable_plane(struct drm_plane *plane)
 +{
 +      if (!plane->fb)
 +              return 0;
 +
 +      if (WARN_ON(!plane->crtc))
 +              return -EINVAL;
 +
 +      return plane->funcs->update_plane(plane, plane->crtc, NULL,
 +                                        0, 0, 0, 0, 0, 0, 0, 0);
 +}
 +
  /* Common destruction function for both primary and cursor planes */
  static void intel_plane_destroy(struct drm_plane *plane)
  {
  }
  
  static const struct drm_plane_funcs intel_primary_plane_funcs = {
 -      .update_plane = intel_primary_plane_setplane,
 -      .disable_plane = intel_primary_plane_disable,
 +      .update_plane = intel_update_plane,
 +      .disable_plane = intel_disable_plane,
        .destroy = intel_plane_destroy,
        .set_property = intel_plane_set_property
  };
@@@ -11968,8 -12026,6 +11968,8 @@@ static struct drm_plane *intel_primary_
        primary->pipe = pipe;
        primary->plane = pipe;
        primary->rotation = BIT(DRM_ROTATE_0);
 +      primary->check_plane = intel_check_primary_plane;
 +      primary->commit_plane = intel_commit_primary_plane;
        if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
                primary->plane = !pipe;
  
        return &primary->base;
  }
  
 -static int
 -intel_cursor_plane_disable(struct drm_plane *plane)
 -{
 -      if (!plane->fb)
 -              return 0;
 -
 -      BUG_ON(!plane->crtc);
 -
 -      return intel_crtc_cursor_set_obj(plane->crtc, NULL, 0, 0);
 -}
 -
  static int
  intel_check_cursor_plane(struct drm_plane *plane,
                         struct intel_plane_state *state)
  {
 -      struct drm_crtc *crtc = state->crtc;
 +      struct drm_crtc *crtc = state->base.crtc;
        struct drm_device *dev = crtc->dev;
 -      struct drm_framebuffer *fb = state->fb;
 +      struct drm_framebuffer *fb = state->base.fb;
        struct drm_rect *dest = &state->dst;
        struct drm_rect *src = &state->src;
        const struct drm_rect *clip = &state->clip;
        return ret;
  }
  
 -static int
 +static void
  intel_commit_cursor_plane(struct drm_plane *plane,
                          struct intel_plane_state *state)
  {
 -      struct drm_crtc *crtc = state->crtc;
 -      struct drm_framebuffer *fb = state->fb;
 +      struct drm_crtc *crtc = state->base.crtc;
 +      struct drm_device *dev = crtc->dev;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_plane *intel_plane = to_intel_plane(plane);
 -      struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 -      struct drm_i915_gem_object *obj = intel_fb->obj;
 -      int crtc_w, crtc_h;
 +      struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
 +      struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
 +      enum pipe pipe = intel_crtc->pipe;
 +      unsigned old_width;
 +      uint32_t addr;
  
 +      plane->fb = state->base.fb;
        crtc->cursor_x = state->orig_dst.x1;
        crtc->cursor_y = state->orig_dst.y1;
  
        intel_plane->src_h = drm_rect_height(&state->orig_src);
        intel_plane->obj = obj;
  
 -      if (fb != crtc->cursor->fb) {
 -              crtc_w = drm_rect_width(&state->orig_dst);
 -              crtc_h = drm_rect_height(&state->orig_dst);
 -              return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h);
 -      } else {
 -              intel_crtc_update_cursor(crtc, state->visible);
 -
 -              intel_frontbuffer_flip(crtc->dev,
 -                                     INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe));
 +      if (intel_crtc->cursor_bo == obj)
 +              goto update;
  
 -              return 0;
 +      /*
 +       * 'prepare' is only called when fb != NULL; we still need to update
 +       * frontbuffer tracking for the 'disable' case here.
 +       */
 +      if (!obj) {
 +              mutex_lock(&dev->struct_mutex);
 +              i915_gem_track_fb(old_obj, NULL,
 +                                INTEL_FRONTBUFFER_CURSOR(pipe));
 +              mutex_unlock(&dev->struct_mutex);
        }
 -}
 -
 -static int
 -intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 -                        struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 -                        unsigned int crtc_w, unsigned int crtc_h,
 -                        uint32_t src_x, uint32_t src_y,
 -                        uint32_t src_w, uint32_t src_h)
 -{
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      struct intel_plane_state state;
 -      int ret;
 -
 -      state.crtc = crtc;
 -      state.fb = fb;
  
 -      /* sample coordinates in 16.16 fixed point */
 -      state.src.x1 = src_x;
 -      state.src.x2 = src_x + src_w;
 -      state.src.y1 = src_y;
 -      state.src.y2 = src_y + src_h;
 -
 -      /* integer pixels */
 -      state.dst.x1 = crtc_x;
 -      state.dst.x2 = crtc_x + crtc_w;
 -      state.dst.y1 = crtc_y;
 -      state.dst.y2 = crtc_y + crtc_h;
 +      if (!obj)
 +              addr = 0;
 +      else if (!INTEL_INFO(dev)->cursor_needs_physical)
 +              addr = i915_gem_obj_ggtt_offset(obj);
 +      else
 +              addr = obj->phys_handle->busaddr;
  
 -      state.clip.x1 = 0;
 -      state.clip.y1 = 0;
 -      state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
 -      state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
 +      intel_crtc->cursor_addr = addr;
 +      intel_crtc->cursor_bo = obj;
 +update:
 +      old_width = intel_crtc->cursor_width;
  
 -      state.orig_src = state.src;
 -      state.orig_dst = state.dst;
 +      intel_crtc->cursor_width = drm_rect_width(&state->orig_dst);
 +      intel_crtc->cursor_height = drm_rect_height(&state->orig_dst);
  
 -      ret = intel_check_cursor_plane(plane, &state);
 -      if (ret)
 -              return ret;
 +      if (intel_crtc->active) {
 +              if (old_width != intel_crtc->cursor_width)
 +                      intel_update_watermarks(crtc);
 +              intel_crtc_update_cursor(crtc, state->visible);
  
 -      return intel_commit_cursor_plane(plane, &state);
 +              intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
 +      }
  }
  
  static const struct drm_plane_funcs intel_cursor_plane_funcs = {
 -      .update_plane = intel_cursor_plane_update,
 -      .disable_plane = intel_cursor_plane_disable,
 +      .update_plane = intel_update_plane,
 +      .disable_plane = intel_disable_plane,
        .destroy = intel_plane_destroy,
        .set_property = intel_plane_set_property,
  };
@@@ -12144,8 -12225,6 +12144,8 @@@ static struct drm_plane *intel_cursor_p
        cursor->pipe = pipe;
        cursor->plane = pipe;
        cursor->rotation = BIT(DRM_ROTATE_0);
 +      cursor->check_plane = intel_check_cursor_plane;
 +      cursor->commit_plane = intel_commit_cursor_plane;
  
        drm_universal_plane_init(dev, &cursor->base, 0,
                                 &intel_cursor_plane_funcs,
@@@ -12304,6 -12383,28 +12304,6 @@@ static bool has_edp_a(struct drm_devic
        return true;
  }
  
 -const char *intel_output_name(int output)
 -{
 -      static const char *names[] = {
 -              [INTEL_OUTPUT_UNUSED] = "Unused",
 -              [INTEL_OUTPUT_ANALOG] = "Analog",
 -              [INTEL_OUTPUT_DVO] = "DVO",
 -              [INTEL_OUTPUT_SDVO] = "SDVO",
 -              [INTEL_OUTPUT_LVDS] = "LVDS",
 -              [INTEL_OUTPUT_TVOUT] = "TV",
 -              [INTEL_OUTPUT_HDMI] = "HDMI",
 -              [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort",
 -              [INTEL_OUTPUT_EDP] = "eDP",
 -              [INTEL_OUTPUT_DSI] = "DSI",
 -              [INTEL_OUTPUT_UNKNOWN] = "Unknown",
 -      };
 -
 -      if (output < 0 || output >= ARRAY_SIZE(names) || !names[output])
 -              return "Invalid";
 -
 -      return names[output];
 -}
 -
  static bool intel_crt_present(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@@ -12956,11 -13057,7 +12956,7 @@@ static void i915_disable_vga(struct drm
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
        udelay(300);
  
-       /*
-        * Fujitsu-Siemens Lifebook S6010 (830) has problems resuming
-        * from S3 without preserving (some of?) the other bits.
-        */
-       I915_WRITE(vga_reg, dev_priv->bios_vgacntr | VGA_DISP_DISABLE);
+       I915_WRITE(vga_reg, VGA_DISP_DISABLE);
        POSTING_READ(vga_reg);
  }
  
@@@ -13045,14 -13142,12 +13041,12 @@@ void intel_modeset_init(struct drm_devi
  
        intel_shared_dpll_init(dev);
  
-       /* save the BIOS value before clobbering it */
-       dev_priv->bios_vgacntr = I915_READ(i915_vgacntrl_reg(dev));
        /* Just disable it once at startup */
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
  
        /* Just in case the BIOS is doing something questionable. */
 -      intel_disable_fbc(dev);
 +      intel_fbc_disable(dev);
  
        drm_modeset_lock_all(dev);
        intel_modeset_setup_hw_state(dev, false);
@@@ -13569,7 -13664,7 +13563,7 @@@ void intel_modeset_cleanup(struct drm_d
  
        intel_unregister_dsm_handler();
  
 -      intel_disable_fbc(dev);
 +      intel_fbc_disable(dev);
  
        ironlake_teardown_rc6(dev);
  
index 588b618ab668fc699153bcc5f655d4ec6d1a8bf6,3b40a17b8852fa7d3ff0519a37baef85c09f467b..bb871f3cfe2e0de18107fc4d55257b1e02326521
@@@ -244,7 -244,8 +244,7 @@@ typedef struct dpll 
  } intel_clock_t;
  
  struct intel_plane_state {
 -      struct drm_crtc *crtc;
 -      struct drm_framebuffer *fb;
 +      struct drm_plane_state base;
        struct drm_rect src;
        struct drm_rect dst;
        struct drm_rect clip;
@@@ -405,7 -406,8 +405,7 @@@ struct intel_pipe_wm 
  };
  
  struct intel_mmio_flip {
 -      u32 seqno;
 -      struct intel_engine_cs *ring;
 +      struct drm_i915_gem_request *req;
        struct work_struct work;
  };
  
@@@ -508,10 -510,6 +508,10 @@@ struct intel_plane 
                             uint32_t src_w, uint32_t src_h);
        void (*disable_plane)(struct drm_plane *plane,
                              struct drm_crtc *crtc);
 +      int (*check_plane)(struct drm_plane *plane,
 +                         struct intel_plane_state *state);
 +      void (*commit_plane)(struct drm_plane *plane,
 +                           struct intel_plane_state *state);
        int (*update_colorkey)(struct drm_plane *plane,
                               struct drm_intel_sprite_colorkey *key);
        void (*get_colorkey)(struct drm_plane *plane,
@@@ -710,7 -708,8 +710,7 @@@ struct intel_unpin_work 
  #define INTEL_FLIP_COMPLETE   2
        u32 flip_count;
        u32 gtt_offset;
 -      struct intel_engine_cs *flip_queued_ring;
 -      u32 flip_queued_seqno;
 +      struct drm_i915_gem_request *flip_queued_req;
        int flip_queued_vblank;
        int flip_ready_vblank;
        bool enable_stall_check;
@@@ -795,6 -794,7 +795,7 @@@ void gen6_disable_pm_irq(struct drm_i91
  void gen6_reset_rps_interrupts(struct drm_device *dev);
  void gen6_enable_rps_interrupts(struct drm_device *dev);
  void gen6_disable_rps_interrupts(struct drm_device *dev);
+ u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask);
  void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
  void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
  static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
@@@ -875,6 -875,7 +876,6 @@@ void intel_audio_codec_enable(struct in
  void intel_audio_codec_disable(struct intel_encoder *encoder);
  
  /* intel_display.c */
 -const char *intel_output_name(int output);
  bool intel_has_pending_fb_unpin(struct drm_device *dev);
  int intel_pch_rawclk(struct drm_device *dev);
  void intel_mark_busy(struct drm_device *dev);
@@@ -925,10 -926,6 +926,10 @@@ void intel_prepare_page_flip(struct drm
  void intel_finish_page_flip(struct drm_device *dev, int pipe);
  void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
  void intel_check_page_flip(struct drm_device *dev, int pipe);
 +int intel_prepare_plane_fb(struct drm_plane *plane,
 +                         struct drm_framebuffer *fb);
 +void intel_cleanup_plane_fb(struct drm_plane *plane,
 +                          struct drm_framebuffer *fb);
  
  /* shared dpll functions */
  struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
@@@ -1014,12 -1011,6 +1015,12 @@@ void intel_dp_hot_plug(struct intel_enc
  void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
  uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
  void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
 +int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 +                     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
 +                     unsigned int crtc_w, unsigned int crtc_h,
 +                     uint32_t src_x, uint32_t src_y,
 +                     uint32_t src_w, uint32_t src_h);
 +int intel_disable_plane(struct drm_plane *plane);
  
  /* intel_dp_mst.c */
  int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@@@ -1063,13 -1054,6 +1064,13 @@@ static inline void intel_fbdev_restore_
  }
  #endif
  
 +/* intel_fbc.c */
 +bool intel_fbc_enabled(struct drm_device *dev);
 +void intel_fbc_update(struct drm_device *dev);
 +void intel_fbc_init(struct drm_i915_private *dev_priv);
 +void intel_fbc_disable(struct drm_device *dev);
 +void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
 +
  /* intel_hdmi.c */
  void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
  void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
@@@ -1100,7 -1084,6 +1101,7 @@@ int intel_overlay_put_image(struct drm_
                            struct drm_file *file_priv);
  int intel_overlay_attrs(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 +void intel_overlay_reset(struct drm_i915_private *dev_priv);
  
  
  /* intel_panel.c */
@@@ -1133,6 -1116,7 +1134,6 @@@ void intel_backlight_unregister(struct 
  
  
  /* intel_psr.c */
 -bool intel_psr_is_enabled(struct drm_device *dev);
  void intel_psr_enable(struct intel_dp *intel_dp);
  void intel_psr_disable(struct intel_dp *intel_dp);
  void intel_psr_invalidate(struct drm_device *dev,
@@@ -1176,6 -1160,8 +1177,6 @@@ void intel_update_sprite_watermarks(str
                                    bool enabled, bool scaled);
  void intel_init_pm(struct drm_device *dev);
  void intel_pm_setup(struct drm_device *dev);
 -bool intel_fbc_enabled(struct drm_device *dev);
 -void intel_update_fbc(struct drm_device *dev);
  void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
  void intel_gpu_ips_teardown(void);
  void intel_init_gt_powersave(struct drm_device *dev);
@@@ -1206,6 -1192,7 +1207,6 @@@ int intel_plane_set_property(struct drm
                             struct drm_property *prop,
                             uint64_t val);
  int intel_plane_restore(struct drm_plane *plane);
 -void intel_plane_disable(struct drm_plane *plane);
  int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
  int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
index a3ebaa87310708138ba4565ee9fa6332c6a0b81b,bf814a64582a3eee53964ce4a8f4a62913b860a7..7d99a9c4e49b0ecd40d37808fdcbee3ec7763087
  #define INTEL_RC6p_ENABLE                     (1<<1)
  #define INTEL_RC6pp_ENABLE                    (1<<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.
 - *
 - * The benefits of FBC are mostly visible with solid backgrounds and
 - * variation-less patterns.
 - *
 - * FBC-related functionality can be enabled by the means of the
 - * i915.i915_enable_fbc parameter
 - */
 -
  static void gen9_init_clock_gating(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
                   _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
  }
  
 -static void i8xx_disable_fbc(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 fbc_ctl;
 -
 -      dev_priv->fbc.enabled = false;
 -
 -      /* Disable compression */
 -      fbc_ctl = I915_READ(FBC_CONTROL);
 -      if ((fbc_ctl & FBC_CTL_EN) == 0)
 -              return;
 -
 -      fbc_ctl &= ~FBC_CTL_EN;
 -      I915_WRITE(FBC_CONTROL, fbc_ctl);
 -
 -      /* Wait for compressing bit to clear */
 -      if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
 -              DRM_DEBUG_KMS("FBC idle timed out\n");
 -              return;
 -      }
 -
 -      DRM_DEBUG_KMS("disabled FBC\n");
 -}
 -
 -static void i8xx_enable_fbc(struct drm_crtc *crtc)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_framebuffer *fb = crtc->primary->fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      int cfb_pitch;
 -      int i;
 -      u32 fbc_ctl;
 -
 -      dev_priv->fbc.enabled = true;
 -
 -      cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
 -      if (fb->pitches[0] < cfb_pitch)
 -              cfb_pitch = fb->pitches[0];
 -
 -      /* FBC_CTL wants 32B or 64B units */
 -      if (IS_GEN2(dev))
 -              cfb_pitch = (cfb_pitch / 32) - 1;
 -      else
 -              cfb_pitch = (cfb_pitch / 64) - 1;
 -
 -      /* Clear old tags */
 -      for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
 -              I915_WRITE(FBC_TAG + (i * 4), 0);
 -
 -      if (IS_GEN4(dev)) {
 -              u32 fbc_ctl2;
 -
 -              /* Set it up... */
 -              fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
 -              fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
 -              I915_WRITE(FBC_CONTROL2, fbc_ctl2);
 -              I915_WRITE(FBC_FENCE_OFF, crtc->y);
 -      }
 -
 -      /* enable it... */
 -      fbc_ctl = I915_READ(FBC_CONTROL);
 -      fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
 -      fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
 -      if (IS_I945GM(dev))
 -              fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
 -      fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
 -      fbc_ctl |= obj->fence_reg;
 -      I915_WRITE(FBC_CONTROL, fbc_ctl);
 -
 -      DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
 -                    cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
 -}
 -
 -static bool i8xx_fbc_enabled(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
 -}
 -
 -static void g4x_enable_fbc(struct drm_crtc *crtc)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_framebuffer *fb = crtc->primary->fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      u32 dpfc_ctl;
 -
 -      dev_priv->fbc.enabled = true;
 -
 -      dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
 -      if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 -              dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 -      else
 -              dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 -      dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
 -
 -      I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
 -
 -      /* enable it... */
 -      I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 -
 -      DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 -}
 -
 -static void g4x_disable_fbc(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 dpfc_ctl;
 -
 -      dev_priv->fbc.enabled = false;
 -
 -      /* Disable compression */
 -      dpfc_ctl = I915_READ(DPFC_CONTROL);
 -      if (dpfc_ctl & DPFC_CTL_EN) {
 -              dpfc_ctl &= ~DPFC_CTL_EN;
 -              I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 -
 -              DRM_DEBUG_KMS("disabled FBC\n");
 -      }
 -}
 -
 -static bool g4x_fbc_enabled(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
 -}
 -
 -static void sandybridge_blit_fbc_update(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 blt_ecoskpd;
 -
 -      /* Make sure blitter notifies FBC of writes */
 -
 -      /* Blitter is part of Media powerwell on VLV. No impact of
 -       * his param in other platforms for now */
 -      gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
 -
 -      blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
 -      blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
 -              GEN6_BLITTER_LOCK_SHIFT;
 -      I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
 -      blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
 -      I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
 -      blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
 -                       GEN6_BLITTER_LOCK_SHIFT);
 -      I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
 -      POSTING_READ(GEN6_BLITTER_ECOSKPD);
 -
 -      gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
 -}
 -
 -static void ironlake_enable_fbc(struct drm_crtc *crtc)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_framebuffer *fb = crtc->primary->fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      u32 dpfc_ctl;
 -
 -      dev_priv->fbc.enabled = true;
 -
 -      dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
 -      if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 -              dev_priv->fbc.threshold++;
 -
 -      switch (dev_priv->fbc.threshold) {
 -      case 4:
 -      case 3:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_4X;
 -              break;
 -      case 2:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 -              break;
 -      case 1:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 -              break;
 -      }
 -      dpfc_ctl |= DPFC_CTL_FENCE_EN;
 -      if (IS_GEN5(dev))
 -              dpfc_ctl |= obj->fence_reg;
 -
 -      I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
 -      I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
 -      /* enable it... */
 -      I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 -
 -      if (IS_GEN6(dev)) {
 -              I915_WRITE(SNB_DPFC_CTL_SA,
 -                         SNB_CPU_FENCE_ENABLE | obj->fence_reg);
 -              I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
 -              sandybridge_blit_fbc_update(dev);
 -      }
 -
 -      DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 -}
 -
 -static void ironlake_disable_fbc(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      u32 dpfc_ctl;
 -
 -      dev_priv->fbc.enabled = false;
 -
 -      /* Disable compression */
 -      dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
 -      if (dpfc_ctl & DPFC_CTL_EN) {
 -              dpfc_ctl &= ~DPFC_CTL_EN;
 -              I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 -
 -              DRM_DEBUG_KMS("disabled FBC\n");
 -      }
 -}
 -
 -static bool ironlake_fbc_enabled(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
 -}
 -
 -static void gen7_enable_fbc(struct drm_crtc *crtc)
 -{
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_framebuffer *fb = crtc->primary->fb;
 -      struct drm_i915_gem_object *obj = intel_fb_obj(fb);
 -      struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 -      u32 dpfc_ctl;
 -
 -      dev_priv->fbc.enabled = true;
 -
 -      dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
 -      if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
 -              dev_priv->fbc.threshold++;
 -
 -      switch (dev_priv->fbc.threshold) {
 -      case 4:
 -      case 3:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_4X;
 -              break;
 -      case 2:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_2X;
 -              break;
 -      case 1:
 -              dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 -              break;
 -      }
 -
 -      dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
 -
 -      if (dev_priv->fbc.false_color)
 -              dpfc_ctl |= FBC_CTL_FALSE_COLOR;
 -
 -      I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 -
 -      if (IS_IVYBRIDGE(dev)) {
 -              /* WaFbcAsynchFlipDisableFbcQueue:ivb */
 -              I915_WRITE(ILK_DISPLAY_CHICKEN1,
 -                         I915_READ(ILK_DISPLAY_CHICKEN1) |
 -                         ILK_FBCQ_DIS);
 -      } else {
 -              /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
 -              I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
 -                         I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
 -                         HSW_FBCQ_DIS);
 -      }
 -
 -      I915_WRITE(SNB_DPFC_CTL_SA,
 -                 SNB_CPU_FENCE_ENABLE | obj->fence_reg);
 -      I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
 -
 -      sandybridge_blit_fbc_update(dev);
 -
 -      DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 -}
 -
 -bool intel_fbc_enabled(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      return dev_priv->fbc.enabled;
 -}
 -
 -void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      if (!IS_GEN8(dev))
 -              return;
 -
 -      if (!intel_fbc_enabled(dev))
 -              return;
 -
 -      I915_WRITE(MSG_FBC_REND_STATE, value);
 -}
 -
 -static void intel_fbc_work_fn(struct work_struct *__work)
 -{
 -      struct intel_fbc_work *work =
 -              container_of(to_delayed_work(__work),
 -                           struct intel_fbc_work, work);
 -      struct drm_device *dev = work->crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      mutex_lock(&dev->struct_mutex);
 -      if (work == dev_priv->fbc.fbc_work) {
 -              /* Double check that we haven't switched fb without cancelling
 -               * the prior work.
 -               */
 -              if (work->crtc->primary->fb == work->fb) {
 -                      dev_priv->display.enable_fbc(work->crtc);
 -
 -                      dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
 -                      dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
 -                      dev_priv->fbc.y = work->crtc->y;
 -              }
 -
 -              dev_priv->fbc.fbc_work = NULL;
 -      }
 -      mutex_unlock(&dev->struct_mutex);
 -
 -      kfree(work);
 -}
 -
 -static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
 -{
 -      if (dev_priv->fbc.fbc_work == NULL)
 -              return;
 -
 -      DRM_DEBUG_KMS("cancelling pending FBC enable\n");
 -
 -      /* Synchronisation is provided by struct_mutex and checking of
 -       * dev_priv->fbc.fbc_work, so we can perform the cancellation
 -       * entirely asynchronously.
 -       */
 -      if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
 -              /* tasklet was killed before being run, clean up */
 -              kfree(dev_priv->fbc.fbc_work);
 -
 -      /* Mark the work as no longer wanted so that if it does
 -       * wake-up (because the work was already running and waiting
 -       * for our mutex), it will discover that is no longer
 -       * necessary to run.
 -       */
 -      dev_priv->fbc.fbc_work = NULL;
 -}
 -
 -static void intel_enable_fbc(struct drm_crtc *crtc)
 -{
 -      struct intel_fbc_work *work;
 -      struct drm_device *dev = crtc->dev;
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      if (!dev_priv->display.enable_fbc)
 -              return;
 -
 -      intel_cancel_fbc_work(dev_priv);
 -
 -      work = kzalloc(sizeof(*work), GFP_KERNEL);
 -      if (work == NULL) {
 -              DRM_ERROR("Failed to allocate FBC work structure\n");
 -              dev_priv->display.enable_fbc(crtc);
 -              return;
 -      }
 -
 -      work->crtc = crtc;
 -      work->fb = crtc->primary->fb;
 -      INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
 -
 -      dev_priv->fbc.fbc_work = work;
 -
 -      /* Delay the actual enabling to let pageflipping cease and the
 -       * display to settle before starting the compression. Note that
 -       * this delay also serves a second purpose: it allows for a
 -       * vblank to pass after disabling the FBC before we attempt
 -       * to modify the control registers.
 -       *
 -       * A more complicated solution would involve tracking vblanks
 -       * following the termination of the page-flipping sequence
 -       * and indeed performing the enable as a co-routine and not
 -       * waiting synchronously upon the vblank.
 -       *
 -       * WaFbcWaitForVBlankBeforeEnable:ilk,snb
 -       */
 -      schedule_delayed_work(&work->work, msecs_to_jiffies(50));
 -}
 -
 -void intel_disable_fbc(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -
 -      intel_cancel_fbc_work(dev_priv);
 -
 -      if (!dev_priv->display.disable_fbc)
 -              return;
 -
 -      dev_priv->display.disable_fbc(dev);
 -      dev_priv->fbc.plane = -1;
 -}
 -
 -static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
 -                            enum no_fbc_reason reason)
 -{
 -      if (dev_priv->fbc.no_fbc_reason == reason)
 -              return false;
 -
 -      dev_priv->fbc.no_fbc_reason = reason;
 -      return true;
 -}
 -
 -/**
 - * intel_update_fbc - enable/disable FBC as needed
 - * @dev: the drm_device
 - *
 - * Set up the framebuffer compression hardware at mode set time.  We
 - * enable it if possible:
 - *   - plane A only (on pre-965)
 - *   - no pixel mulitply/line duplication
 - *   - no alpha buffer discard
 - *   - no dual wide
 - *   - framebuffer <= max_hdisplay in width, max_vdisplay in height
 - *
 - * We can't assume that any compression will take place (worst case),
 - * so the compressed buffer has to be the same size as the uncompressed
 - * one.  It also must reside (along with the line length buffer) in
 - * stolen memory.
 - *
 - * We need to enable/disable FBC on a global basis.
 - */
 -void intel_update_fbc(struct drm_device *dev)
 -{
 -      struct drm_i915_private *dev_priv = dev->dev_private;
 -      struct drm_crtc *crtc = NULL, *tmp_crtc;
 -      struct intel_crtc *intel_crtc;
 -      struct drm_framebuffer *fb;
 -      struct drm_i915_gem_object *obj;
 -      const struct drm_display_mode *adjusted_mode;
 -      unsigned int max_width, max_height;
 -
 -      if (!HAS_FBC(dev)) {
 -              set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
 -              return;
 -      }
 -
 -      if (!i915.powersave) {
 -              if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
 -                      DRM_DEBUG_KMS("fbc disabled per module param\n");
 -              return;
 -      }
 -
 -      /*
 -       * If FBC is already on, we just have to verify that we can
 -       * keep it that way...
 -       * Need to disable if:
 -       *   - more than one pipe is active
 -       *   - changing FBC params (stride, fence, mode)
 -       *   - new fb is too large to fit in compressed buffer
 -       *   - going to an unsupported config (interlace, pixel multiply, etc.)
 -       */
 -      for_each_crtc(dev, tmp_crtc) {
 -              if (intel_crtc_active(tmp_crtc) &&
 -                  to_intel_crtc(tmp_crtc)->primary_enabled) {
 -                      if (crtc) {
 -                              if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
 -                                      DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
 -                              goto out_disable;
 -                      }
 -                      crtc = tmp_crtc;
 -              }
 -      }
 -
 -      if (!crtc || crtc->primary->fb == NULL) {
 -              if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
 -                      DRM_DEBUG_KMS("no output, disabling\n");
 -              goto out_disable;
 -      }
 -
 -      intel_crtc = to_intel_crtc(crtc);
 -      fb = crtc->primary->fb;
 -      obj = intel_fb_obj(fb);
 -      adjusted_mode = &intel_crtc->config.adjusted_mode;
 -
 -      if (i915.enable_fbc < 0) {
 -              if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
 -                      DRM_DEBUG_KMS("disabled per chip default\n");
 -              goto out_disable;
 -      }
 -      if (!i915.enable_fbc) {
 -              if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
 -                      DRM_DEBUG_KMS("fbc disabled per module param\n");
 -              goto out_disable;
 -      }
 -      if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
 -          (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
 -              if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
 -                      DRM_DEBUG_KMS("mode incompatible with compression, "
 -                                    "disabling\n");
 -              goto out_disable;
 -      }
 -
 -      if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
 -              max_width = 4096;
 -              max_height = 4096;
 -      } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
 -              max_width = 4096;
 -              max_height = 2048;
 -      } else {
 -              max_width = 2048;
 -              max_height = 1536;
 -      }
 -      if (intel_crtc->config.pipe_src_w > max_width ||
 -          intel_crtc->config.pipe_src_h > max_height) {
 -              if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
 -                      DRM_DEBUG_KMS("mode too large for compression, disabling\n");
 -              goto out_disable;
 -      }
 -      if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
 -          intel_crtc->plane != PLANE_A) {
 -              if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
 -                      DRM_DEBUG_KMS("plane not A, disabling compression\n");
 -              goto out_disable;
 -      }
 -
 -      /* The use of a CPU fence is mandatory in order to detect writes
 -       * by the CPU to the scanout and trigger updates to the FBC.
 -       */
 -      if (obj->tiling_mode != I915_TILING_X ||
 -          obj->fence_reg == I915_FENCE_REG_NONE) {
 -              if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
 -                      DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
 -              goto out_disable;
 -      }
 -      if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
 -          to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
 -              if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
 -                      DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
 -              goto out_disable;
 -      }
 -
 -      /* If the kernel debugger is active, always disable compression */
 -      if (in_dbg_master())
 -              goto out_disable;
 -
 -      if (i915_gem_stolen_setup_compression(dev, obj->base.size,
 -                                            drm_format_plane_cpp(fb->pixel_format, 0))) {
 -              if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
 -                      DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
 -              goto out_disable;
 -      }
 -
 -      /* If the scanout has not changed, don't modify the FBC settings.
 -       * Note that we make the fundamental assumption that the fb->obj
 -       * cannot be unpinned (and have its GTT offset and fence revoked)
 -       * without first being decoupled from the scanout and FBC disabled.
 -       */
 -      if (dev_priv->fbc.plane == intel_crtc->plane &&
 -          dev_priv->fbc.fb_id == fb->base.id &&
 -          dev_priv->fbc.y == crtc->y)
 -              return;
 -
 -      if (intel_fbc_enabled(dev)) {
 -              /* We update FBC along two paths, after changing fb/crtc
 -               * configuration (modeswitching) and after page-flipping
 -               * finishes. For the latter, we know that not only did
 -               * we disable the FBC at the start of the page-flip
 -               * sequence, but also more than one vblank has passed.
 -               *
 -               * For the former case of modeswitching, it is possible
 -               * to switch between two FBC valid configurations
 -               * instantaneously so we do need to disable the FBC
 -               * before we can modify its control registers. We also
 -               * have to wait for the next vblank for that to take
 -               * effect. However, since we delay enabling FBC we can
 -               * assume that a vblank has passed since disabling and
 -               * that we can safely alter the registers in the deferred
 -               * callback.
 -               *
 -               * In the scenario that we go from a valid to invalid
 -               * and then back to valid FBC configuration we have
 -               * no strict enforcement that a vblank occurred since
 -               * disabling the FBC. However, along all current pipe
 -               * disabling paths we do need to wait for a vblank at
 -               * some point. And we wait before enabling FBC anyway.
 -               */
 -              DRM_DEBUG_KMS("disabling active FBC for update\n");
 -              intel_disable_fbc(dev);
 -      }
 -
 -      intel_enable_fbc(crtc);
 -      dev_priv->fbc.no_fbc_reason = FBC_OK;
 -      return;
 -
 -out_disable:
 -      /* Multiple disables should be harmless */
 -      if (intel_fbc_enabled(dev)) {
 -              DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
 -              intel_disable_fbc(dev);
 -      }
 -      i915_gem_stolen_cleanup_compression(dev);
 -}
  
  static void i915_pineview_get_mem_freq(struct drm_device *dev)
  {
@@@ -2668,8 -3286,7 +2668,8 @@@ static void skl_compute_wm_pipe_paramet
        list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
                struct intel_plane *intel_plane = to_intel_plane(plane);
  
 -              if (intel_plane->pipe == pipe)
 +              if (intel_plane->pipe == pipe &&
 +                      plane->type == DRM_PLANE_TYPE_OVERLAY)
                        p->plane[i++] = intel_plane->wm;
        }
  }
@@@ -3004,8 -3621,9 +3004,8 @@@ static void skl_flush_wm_values(struct 
                    skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
                        skl_wm_flush_pipe(dev_priv, pipe, 2);
                        intel_wait_for_vblank(dev, pipe);
 +                      reallocated[pipe] = true;
                }
 -
 -              reallocated[pipe] = true;
        }
  
        /*
@@@ -3745,16 -4363,7 +3745,7 @@@ static u32 gen6_rps_pm_mask(struct drm_
        mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
        mask &= dev_priv->pm_rps_events;
  
-       /* IVB and SNB hard hangs on looping batchbuffer
-        * if GEN6_PM_UP_EI_EXPIRED is masked.
-        */
-       if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
-               mask |= GEN6_PM_RP_UP_EI_EXPIRED;
-       if (IS_GEN8(dev_priv->dev))
-               mask |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
-       return ~mask;
+       return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
  }
  
  /* gen6_set_rps is called to update the frequency request, but should also be
@@@ -3823,7 -4432,8 +3814,8 @@@ static void vlv_set_rps_idle(struct drm
                return;
  
        /* Mask turbo interrupt so that they will not come in between */
-       I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+       I915_WRITE(GEN6_PMINTRMSK,
+                  gen6_sanitize_rps_pm_mask(dev_priv, ~0));
  
        vlv_force_gfx_clock(dev_priv, true);
  
@@@ -4689,8 -5299,7 +4681,8 @@@ static void cherryview_enable_rps(struc
                I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
        I915_WRITE(GEN6_RC_SLEEP, 0);
  
 -      I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
 +      /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
 +      I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
  
        /* allows RC6 residency counter to work */
        I915_WRITE(VLV_COUNTER_CONTROL,
        /* 3: Enable RC6 */
        if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) &&
                                                (pcbr >> VLV_PCBR_ADDR_SHIFT))
 -              rc6_mode = GEN6_RC_CTL_EI_MODE(1);
 +              rc6_mode = GEN7_RC_CTL_TO_MODE;
  
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
  
@@@ -5064,27 -5673,146 +5056,27 @@@ unsigned long i915_mch_val(struct drm_i
        return ((m * x) / 127) - b;
  }
  
 -static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
 +static int _pxvid_to_vd(u8 pxvid)
 +{
 +      if (pxvid == 0)
 +              return 0;
 +
 +      if (pxvid >= 8 && pxvid < 31)
 +              pxvid = 31;
 +
 +      return (pxvid + 2) * 125;
 +}
 +
 +static u32 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
  {
        struct drm_device *dev = dev_priv->dev;
 -      static const struct v_table {
 -              u16 vd; /* in .1 mil */
 -              u16 vm; /* in .1 mil */
 -      } v_table[] = {
 -              { 0, 0, },
 -              { 375, 0, },
 -              { 500, 0, },
 -              { 625, 0, },
 -              { 750, 0, },
 -              { 875, 0, },
 -              { 1000, 0, },
 -              { 1125, 0, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4125, 3000, },
 -              { 4250, 3125, },
 -              { 4375, 3250, },
 -              { 4500, 3375, },
 -              { 4625, 3500, },
 -              { 4750, 3625, },
 -              { 4875, 3750, },
 -              { 5000, 3875, },
 -              { 5125, 4000, },
 -              { 5250, 4125, },
 -              { 5375, 4250, },
 -              { 5500, 4375, },
 -              { 5625, 4500, },
 -              { 5750, 4625, },
 -              { 5875, 4750, },
 -              { 6000, 4875, },
 -              { 6125, 5000, },
 -              { 6250, 5125, },
 -              { 6375, 5250, },
 -              { 6500, 5375, },
 -              { 6625, 5500, },
 -              { 6750, 5625, },
 -              { 6875, 5750, },
 -              { 7000, 5875, },
 -              { 7125, 6000, },
 -              { 7250, 6125, },
 -              { 7375, 6250, },
 -              { 7500, 6375, },
 -              { 7625, 6500, },
 -              { 7750, 6625, },
 -              { 7875, 6750, },
 -              { 8000, 6875, },
 -              { 8125, 7000, },
 -              { 8250, 7125, },
 -              { 8375, 7250, },
 -              { 8500, 7375, },
 -              { 8625, 7500, },
 -              { 8750, 7625, },
 -              { 8875, 7750, },
 -              { 9000, 7875, },
 -              { 9125, 8000, },
 -              { 9250, 8125, },
 -              { 9375, 8250, },
 -              { 9500, 8375, },
 -              { 9625, 8500, },
 -              { 9750, 8625, },
 -              { 9875, 8750, },
 -              { 10000, 8875, },
 -              { 10125, 9000, },
 -              { 10250, 9125, },
 -              { 10375, 9250, },
 -              { 10500, 9375, },
 -              { 10625, 9500, },
 -              { 10750, 9625, },
 -              { 10875, 9750, },
 -              { 11000, 9875, },
 -              { 11125, 10000, },
 -              { 11250, 10125, },
 -              { 11375, 10250, },
 -              { 11500, 10375, },
 -              { 11625, 10500, },
 -              { 11750, 10625, },
 -              { 11875, 10750, },
 -              { 12000, 10875, },
 -              { 12125, 11000, },
 -              { 12250, 11125, },
 -              { 12375, 11250, },
 -              { 12500, 11375, },
 -              { 12625, 11500, },
 -              { 12750, 11625, },
 -              { 12875, 11750, },
 -              { 13000, 11875, },
 -              { 13125, 12000, },
 -              { 13250, 12125, },
 -              { 13375, 12250, },
 -              { 13500, 12375, },
 -              { 13625, 12500, },
 -              { 13750, 12625, },
 -              { 13875, 12750, },
 -              { 14000, 12875, },
 -              { 14125, 13000, },
 -              { 14250, 13125, },
 -              { 14375, 13250, },
 -              { 14500, 13375, },
 -              { 14625, 13500, },
 -              { 14750, 13625, },
 -              { 14875, 13750, },
 -              { 15000, 13875, },
 -              { 15125, 14000, },
 -              { 15250, 14125, },
 -              { 15375, 14250, },
 -              { 15500, 14375, },
 -              { 15625, 14500, },
 -              { 15750, 14625, },
 -              { 15875, 14750, },
 -              { 16000, 14875, },
 -              { 16125, 15000, },
 -      };
 +      const int vd = _pxvid_to_vd(pxvid);
 +      const int vm = vd - 1125;
 +
        if (INTEL_INFO(dev)->is_mobile)
 -              return v_table[pxvid].vm;
 -      else
 -              return v_table[pxvid].vd;
 +              return vm > 0 ? vm : 0;
 +
 +      return vd;
  }
  
  static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
@@@ -6315,12 -7043,43 +6307,12 @@@ void intel_suspend_hw(struct drm_devic
                lpt_suspend_hw(dev);
  }
  
 -static void intel_init_fbc(struct drm_i915_private *dev_priv)
 -{
 -      if (!HAS_FBC(dev_priv)) {
 -              dev_priv->fbc.enabled = false;
 -              return;
 -      }
 -
 -      if (INTEL_INFO(dev_priv)->gen >= 7) {
 -              dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
 -              dev_priv->display.enable_fbc = gen7_enable_fbc;
 -              dev_priv->display.disable_fbc = ironlake_disable_fbc;
 -      } else if (INTEL_INFO(dev_priv)->gen >= 5) {
 -              dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
 -              dev_priv->display.enable_fbc = ironlake_enable_fbc;
 -              dev_priv->display.disable_fbc = ironlake_disable_fbc;
 -      } else if (IS_GM45(dev_priv)) {
 -              dev_priv->display.fbc_enabled = g4x_fbc_enabled;
 -              dev_priv->display.enable_fbc = g4x_enable_fbc;
 -              dev_priv->display.disable_fbc = g4x_disable_fbc;
 -      } else {
 -              dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
 -              dev_priv->display.enable_fbc = i8xx_enable_fbc;
 -              dev_priv->display.disable_fbc = i8xx_disable_fbc;
 -
 -              /* This value was pulled out of someone's hat */
 -              I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
 -      }
 -
 -      dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
 -}
 -
  /* Set up chip specific power management-related functions */
  void intel_init_pm(struct drm_device *dev)
  {
        struct drm_i915_private *dev_priv = dev->dev_private;
  
 -      intel_init_fbc(dev_priv);
 +      intel_fbc_init(dev_priv);
  
        /* For cxsr */
        if (IS_PINEVIEW(dev))
index 6aa3a81df485669d00514961e73f432e8fffd6fb,ac6da7102fbbdc53c74e584234c51506191da1ee..39e1b071765db89136a2db1cba32f77d54104698
@@@ -118,7 -118,7 +118,7 @@@ bool __intel_display_power_is_enabled(s
  }
  
  /**
 - * intel_display_power_is_enabled - unlocked check for a power domain
 + * intel_display_power_is_enabled - check for a power domain
   * @dev_priv: i915 device instance
   * @domain: power domain to check
   *
@@@ -615,29 -615,6 +615,6 @@@ static void chv_pipe_power_well_disable
                vlv_power_sequencer_reset(dev_priv);
  }
  
- static void check_power_well_state(struct drm_i915_private *dev_priv,
-                                  struct i915_power_well *power_well)
- {
-       bool enabled = power_well->ops->is_enabled(dev_priv, power_well);
-       if (power_well->always_on || !i915.disable_power_well) {
-               if (!enabled)
-                       goto mismatch;
-               return;
-       }
-       if (enabled != (power_well->count > 0))
-               goto mismatch;
-       return;
- mismatch:
-       I915_STATE_WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
-                 power_well->name, power_well->always_on, enabled,
-                 power_well->count, i915.disable_power_well);
- }
  /**
   * intel_display_power_get - grab a power domain reference
   * @dev_priv: i915 device instance
@@@ -669,8 -646,6 +646,6 @@@ void intel_display_power_get(struct drm
                        power_well->ops->enable(dev_priv, power_well);
                        power_well->hw_enabled = true;
                }
-               check_power_well_state(dev_priv, power_well);
        }
  
        power_domains->domain_use_count[domain]++;
@@@ -709,8 -684,6 +684,6 @@@ void intel_display_power_put(struct drm
                        power_well->hw_enabled = false;
                        power_well->ops->disable(dev_priv, power_well);
                }
-               check_power_well_state(dev_priv, power_well);
        }
  
        mutex_unlock(&power_domains->lock);
index 14d173e2a8f7e59044d830a3a1d91a23074ded8b,64fdae558d36e908cca5af2388b22996db975502..ed336fbfab7c50f6f7ddea35115e6ac224157faf
@@@ -5707,28 -5707,6 +5707,28 @@@ void cik_pcie_gart_tlb_flush(struct rad
        WREG32(VM_INVALIDATE_REQUEST, 0x1);
  }
  
 +static void cik_pcie_init_compute_vmid(struct radeon_device *rdev)
 +{
 +      int i;
 +      uint32_t sh_mem_bases, sh_mem_config;
 +
 +      sh_mem_bases = 0x6000 | 0x6000 << 16;
 +      sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
 +      sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
 +
 +      mutex_lock(&rdev->srbm_mutex);
 +      for (i = 8; i < 16; i++) {
 +              cik_srbm_select(rdev, 0, 0, 0, i);
 +              /* CP and shaders */
 +              WREG32(SH_MEM_CONFIG, sh_mem_config);
 +              WREG32(SH_MEM_APE1_BASE, 1);
 +              WREG32(SH_MEM_APE1_LIMIT, 0);
 +              WREG32(SH_MEM_BASES, sh_mem_bases);
 +      }
 +      cik_srbm_select(rdev, 0, 0, 0, 0);
 +      mutex_unlock(&rdev->srbm_mutex);
 +}
 +
  /**
   * cik_pcie_gart_enable - gart enable
   *
@@@ -5842,8 -5820,6 +5842,8 @@@ static int cik_pcie_gart_enable(struct 
        cik_srbm_select(rdev, 0, 0, 0, 0);
        mutex_unlock(&rdev->srbm_mutex);
  
 +      cik_pcie_init_compute_vmid(rdev);
 +
        cik_pcie_gart_tlb_flush(rdev);
        DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
                 (unsigned)(rdev->mc.gtt_size >> 20),
@@@ -6057,6 -6033,17 +6057,17 @@@ void cik_vm_flush(struct radeon_device 
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 1 << vm_id);
  
+       /* wait for the invalidate to complete */
+       radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(0) | /* wait */
+                                WAIT_REG_MEM_FUNCTION(0) |  /* always */
+                                WAIT_REG_MEM_ENGINE(0))); /* me */
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* ref */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, 0x20); /* poll interval */
        /* compute doesn't have PFP */
        if (usepfp) {
                /* sync PFP to ME, otherwise we might get invalid PFP reads */
index 1f4ded181662fa1774f57367c950e63e0d1470a9,a0133c74f4cf8eeff23b3caa04425ea431892c09..479519c24a1f678fe7eaf5e0224763defddcdec8
@@@ -282,33 -282,6 +282,33 @@@ static void cik_sdma_rlc_stop(struct ra
        /* XXX todo */
  }
  
 +/**
 + * cik_sdma_ctx_switch_enable - enable/disable sdma engine preemption
 + *
 + * @rdev: radeon_device pointer
 + * @enable: enable/disable preemption.
 + *
 + * Halt or unhalt the async dma engines (CIK).
 + */
 +void cik_sdma_ctx_switch_enable(struct radeon_device *rdev, bool enable)
 +{
 +      uint32_t reg_offset, value;
 +      int i;
 +
 +      for (i = 0; i < 2; i++) {
 +              if (i == 0)
 +                      reg_offset = SDMA0_REGISTER_OFFSET;
 +              else
 +                      reg_offset = SDMA1_REGISTER_OFFSET;
 +              value = RREG32(SDMA0_CNTL + reg_offset);
 +              if (enable)
 +                      value |= AUTO_CTXSW_ENABLE;
 +              else
 +                      value &= ~AUTO_CTXSW_ENABLE;
 +              WREG32(SDMA0_CNTL + reg_offset, value);
 +      }
 +}
 +
  /**
   * cik_sdma_enable - stop the async dma engines
   *
@@@ -339,8 -312,6 +339,8 @@@ void cik_sdma_enable(struct radeon_devi
                        me_cntl |= SDMA_HALT;
                WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
        }
 +
 +      cik_sdma_ctx_switch_enable(rdev, enable);
  }
  
  /**
@@@ -932,6 -903,9 +932,9 @@@ void cik_sdma_vm_pad_ib(struct radeon_i
  void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
                      unsigned vm_id, uint64_t pd_addr)
  {
+       u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) |
+                         SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        if (vm_id < 8) {
                radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 1 << vm_id);
+       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* reference */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
  }
  
index ddbabab5d875243784391cbba71657db983e1886,8bf87f1203ccaddd85a215dc0c5e19fb48305dbf..7b274205eeaf05d0e2001848a4449091d0962db2
  #include "radeon_kfd.h"
  #include "radeon_ucode.h"
  #include <linux/firmware.h>
 +#include "cik_structs.h"
  
  #define CIK_PIPE_PER_MEC      (4)
  
  struct kgd_mem {
 -      struct radeon_sa_bo *sa_bo;
 +      struct radeon_bo *bo;
        uint64_t gpu_addr;
 -      void *ptr;
 +      void *cpu_ptr;
  };
  
 -static int init_sa_manager(struct kgd_dev *kgd, unsigned int size);
 -static void fini_sa_manager(struct kgd_dev *kgd);
  
 -static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
 -              enum kgd_memory_pool pool, struct kgd_mem **mem);
 +static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
 +                      void **mem_obj, uint64_t *gpu_addr,
 +                      void **cpu_ptr);
  
 -static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem);
 +static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
  
  static uint64_t get_vmem_size(struct kgd_dev *kgd);
  static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
@@@ -64,37 -64,36 +64,37 @@@ static void kgd_program_sh_mem_settings
  static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
                                        unsigned int vmid);
  
 -static int kgd_init_memory(struct kgd_dev *kgd);
 -
  static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
                                uint32_t hpd_size, uint64_t hpd_gpu_addr);
  
  static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr);
 -
 +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd);
- static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
+ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id);
  
  static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id);
 +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
 +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
 +                              unsigned int timeout);
  
  static const struct kfd2kgd_calls kfd2kgd = {
 -      .init_sa_manager = init_sa_manager,
 -      .fini_sa_manager = fini_sa_manager,
 -      .allocate_mem = allocate_mem,
 -      .free_mem = free_mem,
 +      .init_gtt_mem_allocation = alloc_gtt_mem,
 +      .free_gtt_mem = free_gtt_mem,
        .get_vmem_size = get_vmem_size,
        .get_gpu_clock_counter = get_gpu_clock_counter,
        .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
        .program_sh_mem_settings = kgd_program_sh_mem_settings,
        .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
 -      .init_memory = kgd_init_memory,
        .init_pipeline = kgd_init_pipeline,
        .hqd_load = kgd_hqd_load,
-       .hqd_is_occupies = kgd_hqd_is_occupies,
 +      .hqd_sdma_load = kgd_hqd_sdma_load,
+       .hqd_is_occupied = kgd_hqd_is_occupied,
 +      .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
        .hqd_destroy = kgd_hqd_destroy,
 +      .hqd_sdma_destroy = kgd_hqd_sdma_destroy,
        .get_fw_version = get_fw_version
  };
  
@@@ -102,6 -101,7 +102,7 @@@ static const struct kgd2kfd_calls *kgd2
  
  bool radeon_kfd_init(void)
  {
+ #if defined(CONFIG_HSA_AMD_MODULE)
        bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
                                const struct kgd2kfd_calls**);
  
        }
  
        return true;
+ #elif defined(CONFIG_HSA_AMD)
+       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+               kgd2kfd = NULL;
+               return false;
+       }
+       return true;
+ #else
+       return false;
+ #endif
  }
  
  void radeon_kfd_fini(void)
@@@ -183,78 -194,87 +195,78 @@@ int radeon_kfd_resume(struct radeon_dev
        return r;
  }
  
 -static u32 pool_to_domain(enum kgd_memory_pool p)
 -{
 -      switch (p) {
 -      case KGD_POOL_FRAMEBUFFER: return RADEON_GEM_DOMAIN_VRAM;
 -      default: return RADEON_GEM_DOMAIN_GTT;
 -      }
 -}
 -
 -static int init_sa_manager(struct kgd_dev *kgd, unsigned int size)
 +static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
 +                      void **mem_obj, uint64_t *gpu_addr,
 +                      void **cpu_ptr)
  {
        struct radeon_device *rdev = (struct radeon_device *)kgd;
 +      struct kgd_mem **mem = (struct kgd_mem **) mem_obj;
        int r;
  
        BUG_ON(kgd == NULL);
 +      BUG_ON(gpu_addr == NULL);
 +      BUG_ON(cpu_ptr == NULL);
  
 -      r = radeon_sa_bo_manager_init(rdev, &rdev->kfd_bo,
 -                                    size,
 -                                    RADEON_GPU_PAGE_SIZE,
 -                                    RADEON_GEM_DOMAIN_GTT,
 -                                    RADEON_GEM_GTT_WC);
 +      *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
 +      if ((*mem) == NULL)
 +              return -ENOMEM;
  
 -      if (r)
 +      r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
 +                              RADEON_GEM_GTT_WC, NULL, NULL, &(*mem)->bo);
 +      if (r) {
 +              dev_err(rdev->dev,
 +                      "failed to allocate BO for amdkfd (%d)\n", r);
                return r;
 +      }
  
 -      r = radeon_sa_bo_manager_start(rdev, &rdev->kfd_bo);
 -      if (r)
 -              radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
 -
 -      return r;
 -}
 -
 -static void fini_sa_manager(struct kgd_dev *kgd)
 -{
 -      struct radeon_device *rdev = (struct radeon_device *)kgd;
 -
 -      BUG_ON(kgd == NULL);
 -
 -      radeon_sa_bo_manager_suspend(rdev, &rdev->kfd_bo);
 -      radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
 -}
 -
 -static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
 -              enum kgd_memory_pool pool, struct kgd_mem **mem)
 -{
 -      struct radeon_device *rdev = (struct radeon_device *)kgd;
 -      u32 domain;
 -      int r;
 -
 -      BUG_ON(kgd == NULL);
 -
 -      domain = pool_to_domain(pool);
 -      if (domain != RADEON_GEM_DOMAIN_GTT) {
 -              dev_err(rdev->dev,
 -                      "Only allowed to allocate gart memory for kfd\n");
 -              return -EINVAL;
 +      /* map the buffer */
 +      r = radeon_bo_reserve((*mem)->bo, true);
 +      if (r) {
 +              dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r);
 +              goto allocate_mem_reserve_bo_failed;
        }
  
 -      *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
 -      if ((*mem) == NULL)
 -              return -ENOMEM;
 +      r = radeon_bo_pin((*mem)->bo, RADEON_GEM_DOMAIN_GTT,
 +                              &(*mem)->gpu_addr);
 +      if (r) {
 +              dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r);
 +              goto allocate_mem_pin_bo_failed;
 +      }
 +      *gpu_addr = (*mem)->gpu_addr;
  
 -      r = radeon_sa_bo_new(rdev, &rdev->kfd_bo, &(*mem)->sa_bo, size,
 -                              alignment);
 +      r = radeon_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr);
        if (r) {
 -              dev_err(rdev->dev, "failed to get memory for kfd (%d)\n", r);
 -              return r;
 +              dev_err(rdev->dev,
 +                      "(%d) failed to map bo to kernel for amdkfd\n", r);
 +              goto allocate_mem_kmap_bo_failed;
        }
 +      *cpu_ptr = (*mem)->cpu_ptr;
  
 -      (*mem)->ptr = radeon_sa_bo_cpu_addr((*mem)->sa_bo);
 -      (*mem)->gpu_addr = radeon_sa_bo_gpu_addr((*mem)->sa_bo);
 +      radeon_bo_unreserve((*mem)->bo);
  
        return 0;
 +
 +allocate_mem_kmap_bo_failed:
 +      radeon_bo_unpin((*mem)->bo);
 +allocate_mem_pin_bo_failed:
 +      radeon_bo_unreserve((*mem)->bo);
 +allocate_mem_reserve_bo_failed:
 +      radeon_bo_unref(&(*mem)->bo);
 +
 +      return r;
  }
  
 -static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem)
 +static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
  {
 -      struct radeon_device *rdev = (struct radeon_device *)kgd;
 +      struct kgd_mem *mem = (struct kgd_mem *) mem_obj;
  
 -      BUG_ON(kgd == NULL);
 +      BUG_ON(mem == NULL);
  
 -      radeon_sa_bo_free(rdev, &mem->sa_bo, NULL);
 +      radeon_bo_reserve(mem->bo, true);
 +      radeon_bo_kunmap(mem->bo);
 +      radeon_bo_unpin(mem->bo);
 +      radeon_bo_unreserve(mem->bo);
 +      radeon_bo_unref(&(mem->bo));
        kfree(mem);
  }
  
@@@ -370,9 -390,49 +382,13 @@@ static int kgd_set_pasid_vmid_mapping(s
                cpu_relax();
        write_register(kgd, ATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid);
  
+       /* Mapping vmid to pasid also for IH block */
+       write_register(kgd, IH_VMID_0_LUT + vmid * sizeof(uint32_t),
+                       pasid_mapping);
        return 0;
  }
  
 -static int kgd_init_memory(struct kgd_dev *kgd)
 -{
 -      /*
 -       * Configure apertures:
 -       * LDS:         0x60000000'00000000 - 0x60000001'00000000 (4GB)
 -       * Scratch:     0x60000001'00000000 - 0x60000002'00000000 (4GB)
 -       * GPUVM:       0x60010000'00000000 - 0x60020000'00000000 (1TB)
 -       */
 -      int i;
 -      uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000);
 -
 -      for (i = 8; i < 16; i++) {
 -              uint32_t sh_mem_config;
 -
 -              lock_srbm(kgd, 0, 0, 0, i);
 -
 -              sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
 -              sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
 -
 -              write_register(kgd, SH_MEM_CONFIG, sh_mem_config);
 -
 -              write_register(kgd, SH_MEM_BASES, sh_mem_bases);
 -
 -              /* Scratch aperture is not supported for now. */
 -              write_register(kgd, SH_STATIC_MEM_CONFIG, 0);
 -
 -              /* APE1 disabled for now. */
 -              write_register(kgd, SH_MEM_APE1_BASE, 1);
 -              write_register(kgd, SH_MEM_APE1_LIMIT, 0);
 -
 -              unlock_srbm(kgd);
 -      }
 -
 -      return 0;
 -}
 -
  static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
                                uint32_t hpd_size, uint64_t hpd_gpu_addr)
  {
        return 0;
  }
  
 +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m)
 +{
 +      uint32_t retval;
 +
 +      retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET +
 +                      m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET;
 +
 +      pr_debug("kfd: sdma base address: 0x%x\n", retval);
 +
 +      return retval;
 +}
 +
  static inline struct cik_mqd *get_mqd(void *mqd)
  {
        return (struct cik_mqd *)mqd;
  }
  
 +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
 +{
 +      return (struct cik_sdma_rlc_registers *)mqd;
 +}
 +
  static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr)
  {
        return 0;
  }
  
- static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
 +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd)
 +{
 +      struct cik_sdma_rlc_registers *m;
 +      uint32_t sdma_base_addr;
 +
 +      m = get_sdma_mqd(mqd);
 +      sdma_base_addr = get_sdma_base_addr(m);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_VIRTUAL_ADDR,
 +                      m->sdma_rlc_virtual_addr);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_RB_BASE,
 +                      m->sdma_rlc_rb_base);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_RB_BASE_HI,
 +                      m->sdma_rlc_rb_base_hi);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_LO,
 +                      m->sdma_rlc_rb_rptr_addr_lo);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_HI,
 +                      m->sdma_rlc_rb_rptr_addr_hi);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_DOORBELL,
 +                      m->sdma_rlc_doorbell);
 +
 +      write_register(kgd,
 +                      sdma_base_addr + SDMA0_RLC0_RB_CNTL,
 +                      m->sdma_rlc_rb_cntl);
 +
 +      return 0;
 +}
 +
+ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id)
  {
        uint32_t act;
        return retval;
  }
  
 +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
 +{
 +      struct cik_sdma_rlc_registers *m;
 +      uint32_t sdma_base_addr;
 +      uint32_t sdma_rlc_rb_cntl;
 +
 +      m = get_sdma_mqd(mqd);
 +      sdma_base_addr = get_sdma_base_addr(m);
 +
 +      sdma_rlc_rb_cntl = read_register(kgd,
 +                                      sdma_base_addr + SDMA0_RLC0_RB_CNTL);
 +
 +      if (sdma_rlc_rb_cntl & SDMA_RB_ENABLE)
 +              return true;
 +
 +      return false;
 +}
 +
  static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id)
                if (timeout == 0) {
                        pr_err("kfd: cp queue preemption time out (%dms)\n",
                                temp);
+                       release_queue(kgd);
                        return -ETIME;
                }
                msleep(20);
        return 0;
  }
  
 +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
 +                              unsigned int timeout)
 +{
 +      struct cik_sdma_rlc_registers *m;
 +      uint32_t sdma_base_addr;
 +      uint32_t temp;
 +
 +      m = get_sdma_mqd(mqd);
 +      sdma_base_addr = get_sdma_base_addr(m);
 +
 +      temp = read_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL);
 +      temp = temp & ~SDMA_RB_ENABLE;
 +      write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL, temp);
 +
 +      while (true) {
 +              temp = read_register(kgd, sdma_base_addr +
 +                                              SDMA0_RLC0_CONTEXT_STATUS);
 +              if (temp & SDMA_RLC_IDLE)
 +                      break;
 +              if (timeout == 0)
 +                      return -ETIME;
 +              msleep(20);
 +              timeout -= 20;
 +      }
 +
 +      write_register(kgd, sdma_base_addr + SDMA0_RLC0_DOORBELL, 0);
 +      write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_RPTR, 0);
 +      write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_WPTR, 0);
 +      write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_BASE, 0);
 +
 +      return 0;
 +}
 +
  static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type)
  {
        struct radeon_device *rdev = (struct radeon_device *) kgd;