linux/drivers/gpu/drm/i915/i915_gem_tiling.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2008 Intel Corporation
   3 *
   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:
  10 *
  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
  13 * Software.
  14 *
  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
  21 * IN THE SOFTWARE.
  22 *
  23 * Authors:
  24 *    Eric Anholt <eric@anholt.net>
  25 *
  26 */
  27
  28#include <linux/acpi.h>
  29#include <linux/pnp.h>
  30#include "linux/string.h"
  31#include "linux/bitops.h"
  32#include "drmP.h"
  33#include "drm.h"
  34#include "i915_drm.h"
  35#include "i915_drv.h"
  36
  37/** @file i915_gem_tiling.c
  38 *
  39 * Support for managing tiling state of buffer objects.
  40 *
  41 * The idea behind tiling is to increase cache hit rates by rearranging
  42 * pixel data so that a group of pixel accesses are in the same cacheline.
  43 * Performance improvement from doing this on the back/depth buffer are on
  44 * the order of 30%.
  45 *
  46 * Intel architectures make this somewhat more complicated, though, by
  47 * adjustments made to addressing of data when the memory is in interleaved
  48 * mode (matched pairs of DIMMS) to improve memory bandwidth.
  49 * For interleaved memory, the CPU sends every sequential 64 bytes
  50 * to an alternate memory channel so it can get the bandwidth from both.
  51 *
  52 * The GPU also rearranges its accesses for increased bandwidth to interleaved
  53 * memory, and it matches what the CPU does for non-tiled.  However, when tiled
  54 * it does it a little differently, since one walks addresses not just in the
  55 * X direction but also Y.  So, along with alternating channels when bit
  56 * 6 of the address flips, it also alternates when other bits flip --  Bits 9
  57 * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines)
  58 * are common to both the 915 and 965-class hardware.
  59 *
  60 * The CPU also sometimes XORs in higher bits as well, to improve
  61 * bandwidth doing strided access like we do so frequently in graphics.  This
  62 * is called "Channel XOR Randomization" in the MCH documentation.  The result
  63 * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address
  64 * decode.
  65 *
  66 * All of this bit 6 XORing has an effect on our memory management,
  67 * as we need to make sure that the 3d driver can correctly address object
  68 * contents.
  69 *
  70 * If we don't have interleaved memory, all tiling is safe and no swizzling is
  71 * required.
  72 *
  73 * When bit 17 is XORed in, we simply refuse to tile at all.  Bit
  74 * 17 is not just a page offset, so as we page an objet out and back in,
  75 * individual pages in it will have different bit 17 addresses, resulting in
  76 * each 64 bytes being swapped with its neighbor!
  77 *
  78 * Otherwise, if interleaved, we have to tell the 3d driver what the address
  79 * swizzling it needs to do is, since it's writing with the CPU to the pages
  80 * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the
  81 * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling
  82 * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order
  83 * to match what the GPU expects.
  84 */
  85
  86#define MCHBAR_I915 0x44
  87#define MCHBAR_I965 0x48
  88#define MCHBAR_SIZE (4*4096)
  89
  90#define DEVEN_REG 0x54
  91#define   DEVEN_MCHBAR_EN (1 << 28)
  92
  93/* Allocate space for the MCH regs if needed, return nonzero on error */
  94static int
  95intel_alloc_mchbar_resource(struct drm_device *dev)
  96{
  97        drm_i915_private_t *dev_priv = dev->dev_private;
  98        int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
  99        u32 temp_lo, temp_hi = 0;
 100        u64 mchbar_addr;
 101        int ret = 0;
 102
 103        if (IS_I965G(dev))
 104                pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
 105        pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
 106        mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
 107
 108        /* If ACPI doesn't have it, assume we need to allocate it ourselves */
 109#ifdef CONFIG_PNP
 110        if (mchbar_addr &&
 111            pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
 112                ret = 0;
 113                goto out;
 114        }
 115#endif
 116
 117        /* Get some space for it */
 118        ret = pci_bus_alloc_resource(dev_priv->bridge_dev->bus, &dev_priv->mch_res,
 119                                     MCHBAR_SIZE, MCHBAR_SIZE,
 120                                     PCIBIOS_MIN_MEM,
 121                                     0,   pcibios_align_resource,
 122                                     dev_priv->bridge_dev);
 123        if (ret) {
 124                DRM_DEBUG("failed bus alloc: %d\n", ret);
 125                dev_priv->mch_res.start = 0;
 126                goto out;
 127        }
 128
 129        if (IS_I965G(dev))
 130                pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
 131                                       upper_32_bits(dev_priv->mch_res.start));
 132
 133        pci_write_config_dword(dev_priv->bridge_dev, reg,
 134                               lower_32_bits(dev_priv->mch_res.start));
 135out:
 136        return ret;
 137}
 138
 139/* Setup MCHBAR if possible, return true if we should disable it again */
 140static bool
 141intel_setup_mchbar(struct drm_device *dev)
 142{
 143        drm_i915_private_t *dev_priv = dev->dev_private;
 144        int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
 145        u32 temp;
 146        bool need_disable = false, enabled;
 147
 148        if (IS_I915G(dev) || IS_I915GM(dev)) {
 149                pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
 150                enabled = !!(temp & DEVEN_MCHBAR_EN);
 151        } else {
 152                pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
 153                enabled = temp & 1;
 154        }
 155
 156        /* If it's already enabled, don't have to do anything */
 157        if (enabled)
 158                goto out;
 159
 160        if (intel_alloc_mchbar_resource(dev))
 161                goto out;
 162
 163        need_disable = true;
 164
 165        /* Space is allocated or reserved, so enable it. */
 166        if (IS_I915G(dev) || IS_I915GM(dev)) {
 167                pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG,
 168                                       temp | DEVEN_MCHBAR_EN);
 169        } else {
 170                pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
 171                pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp | 1);
 172        }
 173out:
 174        return need_disable;
 175}
 176
 177static void
 178intel_teardown_mchbar(struct drm_device *dev, bool disable)
 179{
 180        drm_i915_private_t *dev_priv = dev->dev_private;
 181        int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
 182        u32 temp;
 183
 184        if (disable) {
 185                if (IS_I915G(dev) || IS_I915GM(dev)) {
 186                        pci_read_config_dword(dev_priv->bridge_dev, DEVEN_REG, &temp);
 187                        temp &= ~DEVEN_MCHBAR_EN;
 188                        pci_write_config_dword(dev_priv->bridge_dev, DEVEN_REG, temp);
 189                } else {
 190                        pci_read_config_dword(dev_priv->bridge_dev, mchbar_reg, &temp);
 191                        temp &= ~1;
 192                        pci_write_config_dword(dev_priv->bridge_dev, mchbar_reg, temp);
 193                }
 194        }
 195
 196        if (dev_priv->mch_res.start)
 197                release_resource(&dev_priv->mch_res);
 198}
 199
 200/**
 201 * Detects bit 6 swizzling of address lookup between IGD access and CPU
 202 * access through main memory.
 203 */
 204void
 205i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
 206{
 207        drm_i915_private_t *dev_priv = dev->dev_private;
 208        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 209        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 210        bool need_disable;
 211
 212        if (IS_IGDNG(dev)) {
 213                /* On IGDNG whatever DRAM config, GPU always do
 214                 * same swizzling setup.
 215                 */
 216                swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 217                swizzle_y = I915_BIT_6_SWIZZLE_9;
 218        } else if (!IS_I9XX(dev)) {
 219                /* As far as we know, the 865 doesn't have these bit 6
 220                 * swizzling issues.
 221                 */
 222                swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 223                swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 224        } else if (IS_MOBILE(dev)) {
 225                uint32_t dcc;
 226
 227                /* Try to make sure MCHBAR is enabled before poking at it */
 228                need_disable = intel_setup_mchbar(dev);
 229
 230                /* On mobile 9xx chipsets, channel interleave by the CPU is
 231                 * determined by DCC.  For single-channel, neither the CPU
 232                 * nor the GPU do swizzling.  For dual channel interleaved,
 233                 * the GPU's interleave is bit 9 and 10 for X tiled, and bit
 234                 * 9 for Y tiled.  The CPU's interleave is independent, and
 235                 * can be based on either bit 11 (haven't seen this yet) or
 236                 * bit 17 (common).
 237                 */
 238                dcc = I915_READ(DCC);
 239                switch (dcc & DCC_ADDRESSING_MODE_MASK) {
 240                case DCC_ADDRESSING_MODE_SINGLE_CHANNEL:
 241                case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC:
 242                        swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 243                        swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 244                        break;
 245                case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED:
 246                        if (dcc & DCC_CHANNEL_XOR_DISABLE) {
 247                                /* This is the base swizzling by the GPU for
 248                                 * tiled buffers.
 249                                 */
 250                                swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 251                                swizzle_y = I915_BIT_6_SWIZZLE_9;
 252                        } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) {
 253                                /* Bit 11 swizzling by the CPU in addition. */
 254                                swizzle_x = I915_BIT_6_SWIZZLE_9_10_11;
 255                                swizzle_y = I915_BIT_6_SWIZZLE_9_11;
 256                        } else {
 257                                /* Bit 17 swizzling by the CPU in addition. */
 258                                swizzle_x = I915_BIT_6_SWIZZLE_9_10_17;
 259                                swizzle_y = I915_BIT_6_SWIZZLE_9_17;
 260                        }
 261                        break;
 262                }
 263                if (dcc == 0xffffffff) {
 264                        DRM_ERROR("Couldn't read from MCHBAR.  "
 265                                  "Disabling tiling.\n");
 266                        swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
 267                        swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 268                }
 269
 270                intel_teardown_mchbar(dev, need_disable);
 271        } else {
 272                /* The 965, G33, and newer, have a very flexible memory
 273                 * configuration.  It will enable dual-channel mode
 274                 * (interleaving) on as much memory as it can, and the GPU
 275                 * will additionally sometimes enable different bit 6
 276                 * swizzling for tiled objects from the CPU.
 277                 *
 278                 * Here's what I found on the G965:
 279                 *    slot fill         memory size  swizzling
 280                 * 0A   0B   1A   1B    1-ch   2-ch
 281                 * 512  0    0    0     512    0     O
 282                 * 512  0    512  0     16     1008  X
 283                 * 512  0    0    512   16     1008  X
 284                 * 0    512  0    512   16     1008  X
 285                 * 1024 1024 1024 0     2048   1024  O
 286                 *
 287                 * We could probably detect this based on either the DRB
 288                 * matching, which was the case for the swizzling required in
 289                 * the table above, or from the 1-ch value being less than
 290                 * the minimum size of a rank.
 291                 */
 292                if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
 293                        swizzle_x = I915_BIT_6_SWIZZLE_NONE;
 294                        swizzle_y = I915_BIT_6_SWIZZLE_NONE;
 295                } else {
 296                        swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 297                        swizzle_y = I915_BIT_6_SWIZZLE_9;
 298                }
 299        }
 300
 301        dev_priv->mm.bit_6_swizzle_x = swizzle_x;
 302        dev_priv->mm.bit_6_swizzle_y = swizzle_y;
 303}
 304
 305
 306/**
 307 * Returns the size of the fence for a tiled object of the given size.
 308 */
 309static int
 310i915_get_fence_size(struct drm_device *dev, int size)
 311{
 312        int i;
 313        int start;
 314
 315        if (IS_I965G(dev)) {
 316                /* The 965 can have fences at any page boundary. */
 317                return ALIGN(size, 4096);
 318        } else {
 319                /* Align the size to a power of two greater than the smallest
 320                 * fence size.
 321                 */
 322                if (IS_I9XX(dev))
 323                        start = 1024 * 1024;
 324                else
 325                        start = 512 * 1024;
 326
 327                for (i = start; i < size; i <<= 1)
 328                        ;
 329
 330                return i;
 331        }
 332}
 333
 334/* Check pitch constriants for all chips & tiling formats */
 335static bool
 336i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
 337{
 338        int tile_width;
 339
 340        /* Linear is always fine */
 341        if (tiling_mode == I915_TILING_NONE)
 342                return true;
 343
 344        if (!IS_I9XX(dev) ||
 345            (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
 346                tile_width = 128;
 347        else
 348                tile_width = 512;
 349
 350        /* check maximum stride & object size */
 351        if (IS_I965G(dev)) {
 352                /* i965 stores the end address of the gtt mapping in the fence
 353                 * reg, so dont bother to check the size */
 354                if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
 355                        return false;
 356        } else if (IS_I9XX(dev)) {
 357                uint32_t pitch_val = ffs(stride / tile_width) - 1;
 358
 359                /* XXX: For Y tiling, FENCE_MAX_PITCH_VAL is actually 6 (8KB)
 360                 * instead of 4 (2KB) on 945s.
 361                 */
 362                if (pitch_val > I915_FENCE_MAX_PITCH_VAL ||
 363                    size > (I830_FENCE_MAX_SIZE_VAL << 20))
 364                        return false;
 365        } else {
 366                uint32_t pitch_val = ffs(stride / tile_width) - 1;
 367
 368                if (pitch_val > I830_FENCE_MAX_PITCH_VAL ||
 369                    size > (I830_FENCE_MAX_SIZE_VAL << 19))
 370                        return false;
 371        }
 372
 373        /* 965+ just needs multiples of tile width */
 374        if (IS_I965G(dev)) {
 375                if (stride & (tile_width - 1))
 376                        return false;
 377                return true;
 378        }
 379
 380        /* Pre-965 needs power of two tile widths */
 381        if (stride < tile_width)
 382                return false;
 383
 384        if (stride & (stride - 1))
 385                return false;
 386
 387        /* We don't 0handle the aperture area covered by the fence being bigger
 388         * than the object size.
 389         */
 390        if (i915_get_fence_size(dev, size) != size)
 391                return false;
 392
 393        return true;
 394}
 395
 396static bool
 397i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
 398{
 399        struct drm_device *dev = obj->dev;
 400        struct drm_i915_gem_object *obj_priv = obj->driver_private;
 401
 402        if (obj_priv->gtt_space == NULL)
 403                return true;
 404
 405        if (tiling_mode == I915_TILING_NONE)
 406                return true;
 407
 408        if (!IS_I965G(dev)) {
 409                if (obj_priv->gtt_offset & (obj->size - 1))
 410                        return false;
 411                if (IS_I9XX(dev)) {
 412                        if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
 413                                return false;
 414                } else {
 415                        if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
 416                                return false;
 417                }
 418        }
 419
 420        return true;
 421}
 422
 423/**
 424 * Sets the tiling mode of an object, returning the required swizzling of
 425 * bit 6 of addresses in the object.
 426 */
 427int
 428i915_gem_set_tiling(struct drm_device *dev, void *data,
 429                   struct drm_file *file_priv)
 430{
 431        struct drm_i915_gem_set_tiling *args = data;
 432        drm_i915_private_t *dev_priv = dev->dev_private;
 433        struct drm_gem_object *obj;
 434        struct drm_i915_gem_object *obj_priv;
 435        int ret = 0;
 436
 437        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 438        if (obj == NULL)
 439                return -EINVAL;
 440        obj_priv = obj->driver_private;
 441
 442        if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
 443                mutex_lock(&dev->struct_mutex);
 444                drm_gem_object_unreference(obj);
 445                mutex_unlock(&dev->struct_mutex);
 446                return -EINVAL;
 447        }
 448
 449        if (args->tiling_mode == I915_TILING_NONE) {
 450                args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 451                args->stride = 0;
 452        } else {
 453                if (args->tiling_mode == I915_TILING_X)
 454                        args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
 455                else
 456                        args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
 457
 458                /* Hide bit 17 swizzling from the user.  This prevents old Mesa
 459                 * from aborting the application on sw fallbacks to bit 17,
 460                 * and we use the pread/pwrite bit17 paths to swizzle for it.
 461                 * If there was a user that was relying on the swizzle
 462                 * information for drm_intel_bo_map()ed reads/writes this would
 463                 * break it, but we don't have any of those.
 464                 */
 465                if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
 466                        args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
 467                if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
 468                        args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
 469
 470                /* If we can't handle the swizzling, make it untiled. */
 471                if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) {
 472                        args->tiling_mode = I915_TILING_NONE;
 473                        args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 474                        args->stride = 0;
 475                }
 476        }
 477
 478        mutex_lock(&dev->struct_mutex);
 479        if (args->tiling_mode != obj_priv->tiling_mode ||
 480            args->stride != obj_priv->stride) {
 481                /* We need to rebind the object if its current allocation
 482                 * no longer meets the alignment restrictions for its new
 483                 * tiling mode. Otherwise we can just leave it alone, but
 484                 * need to ensure that any fence register is cleared.
 485                 */
 486                if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
 487                    ret = i915_gem_object_unbind(obj);
 488                else
 489                    ret = i915_gem_object_put_fence_reg(obj);
 490                if (ret != 0) {
 491                        WARN(ret != -ERESTARTSYS,
 492                             "failed to reset object for tiling switch");
 493                        args->tiling_mode = obj_priv->tiling_mode;
 494                        args->stride = obj_priv->stride;
 495                        goto err;
 496                }
 497
 498                /* If we've changed tiling, GTT-mappings of the object
 499                 * need to re-fault to ensure that the correct fence register
 500                 * setup is in place.
 501                 */
 502                i915_gem_release_mmap(obj);
 503
 504                obj_priv->tiling_mode = args->tiling_mode;
 505                obj_priv->stride = args->stride;
 506        }
 507err:
 508        drm_gem_object_unreference(obj);
 509        mutex_unlock(&dev->struct_mutex);
 510
 511        return ret;
 512}
 513
 514/**
 515 * Returns the current tiling mode and required bit 6 swizzling for the object.
 516 */
 517int
 518i915_gem_get_tiling(struct drm_device *dev, void *data,
 519                   struct drm_file *file_priv)
 520{
 521        struct drm_i915_gem_get_tiling *args = data;
 522        drm_i915_private_t *dev_priv = dev->dev_private;
 523        struct drm_gem_object *obj;
 524        struct drm_i915_gem_object *obj_priv;
 525
 526        obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 527        if (obj == NULL)
 528                return -EINVAL;
 529        obj_priv = obj->driver_private;
 530
 531        mutex_lock(&dev->struct_mutex);
 532
 533        args->tiling_mode = obj_priv->tiling_mode;
 534        switch (obj_priv->tiling_mode) {
 535        case I915_TILING_X:
 536                args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x;
 537                break;
 538        case I915_TILING_Y:
 539                args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y;
 540                break;
 541        case I915_TILING_NONE:
 542                args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
 543                break;
 544        default:
 545                DRM_ERROR("unknown tiling mode\n");
 546        }
 547
 548        /* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
 549        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17)
 550                args->swizzle_mode = I915_BIT_6_SWIZZLE_9;
 551        if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17)
 552                args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10;
 553
 554        drm_gem_object_unreference(obj);
 555        mutex_unlock(&dev->struct_mutex);
 556
 557        return 0;
 558}
 559
 560/**
 561 * Swap every 64 bytes of this page around, to account for it having a new
 562 * bit 17 of its physical address and therefore being interpreted differently
 563 * by the GPU.
 564 */
 565static int
 566i915_gem_swizzle_page(struct page *page)
 567{
 568        char *vaddr;
 569        int i;
 570        char temp[64];
 571
 572        vaddr = kmap(page);
 573        if (vaddr == NULL)
 574                return -ENOMEM;
 575
 576        for (i = 0; i < PAGE_SIZE; i += 128) {
 577                memcpy(temp, &vaddr[i], 64);
 578                memcpy(&vaddr[i], &vaddr[i + 64], 64);
 579                memcpy(&vaddr[i + 64], temp, 64);
 580        }
 581
 582        kunmap(page);
 583
 584        return 0;
 585}
 586
 587void
 588i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj)
 589{
 590        struct drm_device *dev = obj->dev;
 591        drm_i915_private_t *dev_priv = dev->dev_private;
 592        struct drm_i915_gem_object *obj_priv = obj->driver_private;
 593        int page_count = obj->size >> PAGE_SHIFT;
 594        int i;
 595
 596        if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
 597                return;
 598
 599        if (obj_priv->bit_17 == NULL)
 600                return;
 601
 602        for (i = 0; i < page_count; i++) {
 603                char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
 604                if ((new_bit_17 & 0x1) !=
 605                    (test_bit(i, obj_priv->bit_17) != 0)) {
 606                        int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
 607                        if (ret != 0) {
 608                                DRM_ERROR("Failed to swizzle page\n");
 609                                return;
 610                        }
 611                        set_page_dirty(obj_priv->pages[i]);
 612                }
 613        }
 614}
 615
 616void
 617i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj)
 618{
 619        struct drm_device *dev = obj->dev;
 620        drm_i915_private_t *dev_priv = dev->dev_private;
 621        struct drm_i915_gem_object *obj_priv = obj->driver_private;
 622        int page_count = obj->size >> PAGE_SHIFT;
 623        int i;
 624
 625        if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17)
 626                return;
 627
 628        if (obj_priv->bit_17 == NULL) {
 629                obj_priv->bit_17 = kmalloc(BITS_TO_LONGS(page_count) *
 630                                           sizeof(long), GFP_KERNEL);
 631                if (obj_priv->bit_17 == NULL) {
 632                        DRM_ERROR("Failed to allocate memory for bit 17 "
 633                                  "record\n");
 634                        return;
 635                }
 636        }
 637
 638        for (i = 0; i < page_count; i++) {
 639                if (page_to_phys(obj_priv->pages[i]) & (1 << 17))
 640                        __set_bit(i, obj_priv->bit_17);
 641                else
 642                        __clear_bit(i, obj_priv->bit_17);
 643        }
 644}
 645
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.