2  * Copyright © 2008 Intel Corporation
 
   4  * Permission is hereby granted, free of charge, to any person obtaining a
 
   5  * copy of this software and associated documentation files (the "Software"),
 
   6  * to deal in the Software without restriction, including without limitation
 
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
   8  * and/or sell copies of the Software, and to permit persons to whom the
 
   9  * Software is furnished to do so, subject to the following conditions:
 
  11  * The above copyright notice and this permission notice (including the next
 
  12  * paragraph) shall be included in all copies or substantial portions of the
 
  15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
  16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
  17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
  18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
  19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
  20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
  24  *    Eric Anholt <eric@anholt.net>
 
  33 /** @file i915_gem_tiling.c
 
  35  * Support for managing tiling state of buffer objects.
 
  37  * The idea behind tiling is to increase cache hit rates by rearranging
 
  38  * pixel data so that a group of pixel accesses are in the same cacheline.
 
  39  * Performance improvement from doing this on the back/depth buffer are on
 
  42  * Intel architectures make this somewhat more complicated, though, by
 
  43  * adjustments made to addressing of data when the memory is in interleaved
 
  44  * mode (matched pairs of DIMMS) to improve memory bandwidth.
 
  45  * For interleaved memory, the CPU sends every sequential 64 bytes
 
  46  * to an alternate memory channel so it can get the bandwidth from both.
 
  48  * The GPU also rearranges its accesses for increased bandwidth to interleaved
 
  49  * memory, and it matches what the CPU does for non-tiled.  However, when tiled
 
  50  * it does it a little differently, since one walks addresses not just in the
 
  51  * X direction but also Y.  So, along with alternating channels when bit
 
  52  * 6 of the address flips, it also alternates when other bits flip --  Bits 9
 
  53  * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
 
  54  * are common to both the 915 and 965-class hardware.
 
  56  * The CPU also sometimes XORs in higher bits as well, to improve
 
  57  * bandwidth doing strided access like we do so frequently in graphics.  This
 
  58  * is called "Channel XOR Randomization" in the MCH documentation.  The result
 
  59  * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
 
  62  * All of this bit 6 XORing has an effect on our memory management,
 
  63  * as we need to make sure that the 3d driver can correctly address object
 
  66  * If we don't have interleaved memory, all tiling is safe and no swizzling is
 
  69  * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
 
  70  * 17 is not just a page offset, so as we page an objet out and back in,
 
  71  * individual pages in it will have different bit 17 addresses, resulting in
 
  72  * each 64 bytes being swapped with its neighbor!
 
  74  * Otherwise, if interleaved, we have to tell the 3d driver what the address
 
  75  * swizzling it needs to do is, since it's writing with the CPU to the pages
 
  76  * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
 
  77  * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
 
  78  * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
 
  79  * to match what the GPU expects.
 
  83  * Detects bit 6 swizzling of address lookup between IGD access and CPU
 
  84  * access through main memory.
 
  87 i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
 
  89         drm_i915_private_t *dev_priv = dev->dev_private;
 
  90         uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 
  91         uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
  94                 /* As far as we know, the 865 doesn't have these bit 6
 
  97                 swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 
  98                 swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 
  99         } else if ((!IS_I965G(dev) && !IS_G33(dev)) || IS_I965GM(dev) ||
 
 103                 /* On 915-945 and GM965, channel interleave by the CPU is
 
 104                  * determined by DCC.  The CPU will alternate based on bit 6
 
 105                  * in interleaved mode, and the GPU will then also alternate
 
 106                  * on bit 6, 9, and 10 for X, but the CPU may also optionally
 
 107                  * alternate based on bit 17 (XOR not disabled and XOR
 
 110                 dcc = I915_READ(DCC);
 
 111                 switch (dcc & DCC_ADDRESSING_MODE_MASK) {
 
 112                 case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
 
 113                 case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
 
 114                         swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 
 115                         swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 
 117                 case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
 
 118                         if (IS_I915G(dev) || IS_I915GM(dev) ||
 
 119                             dcc & DCC_CHANNEL_XOR_DISABLE) {
 
 120                                 swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 
 121                                 swizzle_y = I915_BIT_6_SWIZZLE_9;
 
 122                         } else if ((IS_I965GM(dev) || IS_GM45(dev)) &&
 
 123                                    (dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
 
 124                                 /* GM965/GM45 does either bit 11 or bit 17
 
 127                                 swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
 
 128                                 swizzle_y = I915_BIT_6_SWIZZLE_9_11;
 
 130                                 /* Bit 17 or perhaps other swizzling */
 
 131                                 swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 
 132                                 swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
 136                 if (dcc == 0xffffffff) {
 
 137                         DRM_ERROR("Couldn't read from MCHBAR.  "
 
 138                                   "Disabling tiling.\n");
 
 139                         swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 
 140                         swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
 143                 /* The 965, G33, and newer, have a very flexible memory
 
 144                  * configuration.  It will enable dual-channel mode
 
 145                  * (interleaving) on as much memory as it can, and the GPU
 
 146                  * will additionally sometimes enable different bit 6
 
 147                  * swizzling for tiled objects from the CPU.
 
 149                  * Here's what I found on the G965:
 
 150                  *    slot fill         memory size  swizzling
 
 151                  * 0A   0B   1A   1B    1-ch   2-ch
 
 153                  * 512  0    512  0     16     1008  X
 
 154                  * 512  0    0    512   16     1008  X
 
 155                  * 0    512  0    512   16     1008  X
 
 156                  * 1024 1024 1024 0     2048   1024  O
 
 158                  * We could probably detect this based on either the DRB
 
 159                  * matching, which was the case for the swizzling required in
 
 160                  * the table above, or from the 1-ch value being less than
 
 161                  * the minimum size of a rank.
 
 163                 if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
 
 164                         swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 
 165                         swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 
 167                         swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 
 168                         swizzle_y = I915_BIT_6_SWIZZLE_9;
 
 172         dev_priv->mm.bit_6_swizzle_x = swizzle_x;
 
 173         dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 
 177  * Sets the tiling mode of an object, returning the required swizzling of
 
 178  * bit 6 of addresses in the object.
 
 181 i915_gem_set_tiling(struct drm_device *dev, void *data,
 
 182                    struct drm_file *file_priv)
 
 184         struct drm_i915_gem_set_tiling *args = data;
 
 185         drm_i915_private_t *dev_priv = dev->dev_private;
 
 186         struct drm_gem_object *obj;
 
 187         struct drm_i915_gem_object *obj_priv;
 
 189         obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 
 192         obj_priv = obj->driver_private;
 
 194         mutex_lock(&dev->struct_mutex);
 
 196         if (args->tiling_mode == I915_TILING_NONE) {
 
 197                 obj_priv->tiling_mode = I915_TILING_NONE;
 
 198                 args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 
 200                 if (args->tiling_mode == I915_TILING_X)
 
 201                         args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
 
 203                         args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
 
 204                 /* If we can't handle the swizzling, make it untiled. */
 
 205                 if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
 
 206                         args->tiling_mode = I915_TILING_NONE;
 
 207                         args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 
 210         obj_priv->tiling_mode = args->tiling_mode;
 
 211         obj_priv->stride = args->stride;
 
 213         mutex_unlock(&dev->struct_mutex);
 
 215         drm_gem_object_unreference(obj);
 
 221  * Returns the current tiling mode and required bit 6 swizzling for the object.
 
 224 i915_gem_get_tiling(struct drm_device *dev, void *data,
 
 225                    struct drm_file *file_priv)
 
 227         struct drm_i915_gem_get_tiling *args = data;
 
 228         drm_i915_private_t *dev_priv = dev->dev_private;
 
 229         struct drm_gem_object *obj;
 
 230         struct drm_i915_gem_object *obj_priv;
 
 232         obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 
 235         obj_priv = obj->driver_private;
 
 237         mutex_lock(&dev->struct_mutex);
 
 239         args->tiling_mode = obj_priv->tiling_mode;
 
 240         switch (obj_priv->tiling_mode) {
 
 242                 args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
 
 245                 args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
 
 247         case I915_TILING_NONE:
 
 248                 args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 
 251                 DRM_ERROR("unknown tiling mode\n");
 
 254         mutex_unlock(&dev->struct_mutex);
 
 256         drm_gem_object_unreference(obj);