linux/drivers/gpu/drm/i915/gvt/cfg_space.c
<<
>>
Prefs
   1/*
   2 * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
   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 FROM,
  20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21 * SOFTWARE.
  22 *
  23 * Authors:
  24 *    Eddie Dong <eddie.dong@intel.com>
  25 *    Jike Song <jike.song@intel.com>
  26 *
  27 * Contributors:
  28 *    Zhi Wang <zhi.a.wang@intel.com>
  29 *    Min He <min.he@intel.com>
  30 *    Bing Niu <bing.niu@intel.com>
  31 *
  32 */
  33
  34#include "i915_drv.h"
  35#include "gvt.h"
  36
  37enum {
  38        INTEL_GVT_PCI_BAR_GTTMMIO = 0,
  39        INTEL_GVT_PCI_BAR_APERTURE,
  40        INTEL_GVT_PCI_BAR_PIO,
  41        INTEL_GVT_PCI_BAR_MAX,
  42};
  43
  44/* bitmap for writable bits (RW or RW1C bits, but cannot co-exist in one
  45 * byte) byte by byte in standard pci configuration space. (not the full
  46 * 256 bytes.)
  47 */
  48static const u8 pci_cfg_space_rw_bmp[PCI_INTERRUPT_LINE + 4] = {
  49        [PCI_COMMAND]           = 0xff, 0x07,
  50        [PCI_STATUS]            = 0x00, 0xf9, /* the only one RW1C byte */
  51        [PCI_CACHE_LINE_SIZE]   = 0xff,
  52        [PCI_BASE_ADDRESS_0 ... PCI_CARDBUS_CIS - 1] = 0xff,
  53        [PCI_ROM_ADDRESS]       = 0x01, 0xf8, 0xff, 0xff,
  54        [PCI_INTERRUPT_LINE]    = 0xff,
  55};
  56
  57/**
  58 * vgpu_pci_cfg_mem_write - write virtual cfg space memory
  59 * @vgpu: target vgpu
  60 * @off: offset
  61 * @src: src ptr to write
  62 * @bytes: number of bytes
  63 *
  64 * Use this function to write virtual cfg space memory.
  65 * For standard cfg space, only RW bits can be changed,
  66 * and we emulates the RW1C behavior of PCI_STATUS register.
  67 */
  68static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
  69                                   u8 *src, unsigned int bytes)
  70{
  71        u8 *cfg_base = vgpu_cfg_space(vgpu);
  72        u8 mask, new, old;
  73        pci_power_t pwr;
  74        int i = 0;
  75
  76        for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) {
  77                mask = pci_cfg_space_rw_bmp[off + i];
  78                old = cfg_base[off + i];
  79                new = src[i] & mask;
  80
  81                /**
  82                 * The PCI_STATUS high byte has RW1C bits, here
  83                 * emulates clear by writing 1 for these bits.
  84                 * Writing a 0b to RW1C bits has no effect.
  85                 */
  86                if (off + i == PCI_STATUS + 1)
  87                        new = (~new & old) & mask;
  88
  89                cfg_base[off + i] = (old & ~mask) | new;
  90        }
  91
  92        /* For other configuration space directly copy as it is. */
  93        if (i < bytes)
  94                memcpy(cfg_base + off + i, src + i, bytes - i);
  95
  96        if (off == vgpu->cfg_space.pmcsr_off && vgpu->cfg_space.pmcsr_off) {
  97                pwr = (pci_power_t __force)(*(u16*)(&vgpu_cfg_space(vgpu)[off])
  98                        & PCI_PM_CTRL_STATE_MASK);
  99                if (pwr == PCI_D3hot)
 100                        vgpu->d3_entered = true;
 101                gvt_dbg_core("vgpu-%d power status changed to %d\n",
 102                             vgpu->id, pwr);
 103        }
 104}
 105
 106/**
 107 * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read
 108 * @vgpu: target vgpu
 109 * @offset: offset
 110 * @p_data: return data ptr
 111 * @bytes: number of bytes to read
 112 *
 113 * Returns:
 114 * Zero on success, negative error code if failed.
 115 */
 116int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
 117        void *p_data, unsigned int bytes)
 118{
 119        struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
 120
 121        if (drm_WARN_ON(&i915->drm, bytes > 4))
 122                return -EINVAL;
 123
 124        if (drm_WARN_ON(&i915->drm,
 125                        offset + bytes > vgpu->gvt->device_info.cfg_space_size))
 126                return -EINVAL;
 127
 128        memcpy(p_data, vgpu_cfg_space(vgpu) + offset, bytes);
 129        return 0;
 130}
 131
 132static int map_aperture(struct intel_vgpu *vgpu, bool map)
 133{
 134        phys_addr_t aperture_pa = vgpu_aperture_pa_base(vgpu);
 135        unsigned long aperture_sz = vgpu_aperture_sz(vgpu);
 136        u64 first_gfn;
 137        u64 val;
 138        int ret;
 139
 140        if (map == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked)
 141                return 0;
 142
 143        val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_2];
 144        if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
 145                val = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
 146        else
 147                val = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_2);
 148
 149        first_gfn = (val + vgpu_aperture_offset(vgpu)) >> PAGE_SHIFT;
 150
 151        ret = intel_gvt_hypervisor_map_gfn_to_mfn(vgpu, first_gfn,
 152                                                  aperture_pa >> PAGE_SHIFT,
 153                                                  aperture_sz >> PAGE_SHIFT,
 154                                                  map);
 155        if (ret)
 156                return ret;
 157
 158        vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].tracked = map;
 159        return 0;
 160}
 161
 162static int trap_gttmmio(struct intel_vgpu *vgpu, bool trap)
 163{
 164        u64 start, end;
 165        u64 val;
 166        int ret;
 167
 168        if (trap == vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked)
 169                return 0;
 170
 171        val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0];
 172        if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
 173                start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
 174        else
 175                start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
 176
 177        start &= ~GENMASK(3, 0);
 178        end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1;
 179
 180        ret = intel_gvt_hypervisor_set_trap_area(vgpu, start, end, trap);
 181        if (ret)
 182                return ret;
 183
 184        vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].tracked = trap;
 185        return 0;
 186}
 187
 188static int emulate_pci_command_write(struct intel_vgpu *vgpu,
 189        unsigned int offset, void *p_data, unsigned int bytes)
 190{
 191        u8 old = vgpu_cfg_space(vgpu)[offset];
 192        u8 new = *(u8 *)p_data;
 193        u8 changed = old ^ new;
 194        int ret;
 195
 196        vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
 197        if (!(changed & PCI_COMMAND_MEMORY))
 198                return 0;
 199
 200        if (old & PCI_COMMAND_MEMORY) {
 201                ret = trap_gttmmio(vgpu, false);
 202                if (ret)
 203                        return ret;
 204                ret = map_aperture(vgpu, false);
 205                if (ret)
 206                        return ret;
 207        } else {
 208                ret = trap_gttmmio(vgpu, true);
 209                if (ret)
 210                        return ret;
 211                ret = map_aperture(vgpu, true);
 212                if (ret)
 213                        return ret;
 214        }
 215
 216        return 0;
 217}
 218
 219static int emulate_pci_rom_bar_write(struct intel_vgpu *vgpu,
 220        unsigned int offset, void *p_data, unsigned int bytes)
 221{
 222        u32 *pval = (u32 *)(vgpu_cfg_space(vgpu) + offset);
 223        u32 new = *(u32 *)(p_data);
 224
 225        if ((new & PCI_ROM_ADDRESS_MASK) == PCI_ROM_ADDRESS_MASK)
 226                /* We don't have rom, return size of 0. */
 227                *pval = 0;
 228        else
 229                vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
 230        return 0;
 231}
 232
 233static int emulate_pci_bar_write(struct intel_vgpu *vgpu, unsigned int offset,
 234        void *p_data, unsigned int bytes)
 235{
 236        u32 new = *(u32 *)(p_data);
 237        bool lo = IS_ALIGNED(offset, 8);
 238        u64 size;
 239        int ret = 0;
 240        bool mmio_enabled =
 241                vgpu_cfg_space(vgpu)[PCI_COMMAND] & PCI_COMMAND_MEMORY;
 242        struct intel_vgpu_pci_bar *bars = vgpu->cfg_space.bar;
 243
 244        /*
 245         * Power-up software can determine how much address
 246         * space the device requires by writing a value of
 247         * all 1's to the register and then reading the value
 248         * back. The device will return 0's in all don't-care
 249         * address bits.
 250         */
 251        if (new == 0xffffffff) {
 252                switch (offset) {
 253                case PCI_BASE_ADDRESS_0:
 254                case PCI_BASE_ADDRESS_1:
 255                        size = ~(bars[INTEL_GVT_PCI_BAR_GTTMMIO].size -1);
 256                        intel_vgpu_write_pci_bar(vgpu, offset,
 257                                                size >> (lo ? 0 : 32), lo);
 258                        /*
 259                         * Untrap the BAR, since guest hasn't configured a
 260                         * valid GPA
 261                         */
 262                        ret = trap_gttmmio(vgpu, false);
 263                        break;
 264                case PCI_BASE_ADDRESS_2:
 265                case PCI_BASE_ADDRESS_3:
 266                        size = ~(bars[INTEL_GVT_PCI_BAR_APERTURE].size -1);
 267                        intel_vgpu_write_pci_bar(vgpu, offset,
 268                                                size >> (lo ? 0 : 32), lo);
 269                        ret = map_aperture(vgpu, false);
 270                        break;
 271                default:
 272                        /* Unimplemented BARs */
 273                        intel_vgpu_write_pci_bar(vgpu, offset, 0x0, false);
 274                }
 275        } else {
 276                switch (offset) {
 277                case PCI_BASE_ADDRESS_0:
 278                case PCI_BASE_ADDRESS_1:
 279                        /*
 280                         * Untrap the old BAR first, since guest has
 281                         * re-configured the BAR
 282                         */
 283                        trap_gttmmio(vgpu, false);
 284                        intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
 285                        ret = trap_gttmmio(vgpu, mmio_enabled);
 286                        break;
 287                case PCI_BASE_ADDRESS_2:
 288                case PCI_BASE_ADDRESS_3:
 289                        map_aperture(vgpu, false);
 290                        intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
 291                        ret = map_aperture(vgpu, mmio_enabled);
 292                        break;
 293                default:
 294                        intel_vgpu_write_pci_bar(vgpu, offset, new, lo);
 295                }
 296        }
 297        return ret;
 298}
 299
 300/**
 301 * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space write
 302 * @vgpu: target vgpu
 303 * @offset: offset
 304 * @p_data: write data ptr
 305 * @bytes: number of bytes to write
 306 *
 307 * Returns:
 308 * Zero on success, negative error code if failed.
 309 */
 310int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
 311        void *p_data, unsigned int bytes)
 312{
 313        struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
 314        int ret;
 315
 316        if (drm_WARN_ON(&i915->drm, bytes > 4))
 317                return -EINVAL;
 318
 319        if (drm_WARN_ON(&i915->drm,
 320                        offset + bytes > vgpu->gvt->device_info.cfg_space_size))
 321                return -EINVAL;
 322
 323        /* First check if it's PCI_COMMAND */
 324        if (IS_ALIGNED(offset, 2) && offset == PCI_COMMAND) {
 325                if (drm_WARN_ON(&i915->drm, bytes > 2))
 326                        return -EINVAL;
 327                return emulate_pci_command_write(vgpu, offset, p_data, bytes);
 328        }
 329
 330        switch (rounddown(offset, 4)) {
 331        case PCI_ROM_ADDRESS:
 332                if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
 333                        return -EINVAL;
 334                return emulate_pci_rom_bar_write(vgpu, offset, p_data, bytes);
 335
 336        case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_5:
 337                if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
 338                        return -EINVAL;
 339                return emulate_pci_bar_write(vgpu, offset, p_data, bytes);
 340
 341        case INTEL_GVT_PCI_SWSCI:
 342                if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
 343                        return -EINVAL;
 344                ret = intel_vgpu_emulate_opregion_request(vgpu, *(u32 *)p_data);
 345                if (ret)
 346                        return ret;
 347                break;
 348
 349        case INTEL_GVT_PCI_OPREGION:
 350                if (drm_WARN_ON(&i915->drm, !IS_ALIGNED(offset, 4)))
 351                        return -EINVAL;
 352                ret = intel_vgpu_opregion_base_write_handler(vgpu,
 353                                                   *(u32 *)p_data);
 354                if (ret)
 355                        return ret;
 356
 357                vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
 358                break;
 359        default:
 360                vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
 361                break;
 362        }
 363        return 0;
 364}
 365
 366/**
 367 * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU
 368 *
 369 * @vgpu: a vGPU
 370 * @primary: is the vGPU presented as primary
 371 *
 372 */
 373void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
 374                               bool primary)
 375{
 376        struct intel_gvt *gvt = vgpu->gvt;
 377        struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
 378        const struct intel_gvt_device_info *info = &gvt->device_info;
 379        u16 *gmch_ctl;
 380        u8 next;
 381
 382        memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
 383               info->cfg_space_size);
 384
 385        if (!primary) {
 386                vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
 387                        INTEL_GVT_PCI_CLASS_VGA_OTHER;
 388                vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
 389                        INTEL_GVT_PCI_CLASS_VGA_OTHER;
 390        }
 391
 392        /* Show guest that there isn't any stolen memory.*/
 393        gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
 394        *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
 395
 396        intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
 397                                 gvt_aperture_pa_base(gvt), true);
 398
 399        vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
 400                                             | PCI_COMMAND_MEMORY
 401                                             | PCI_COMMAND_MASTER);
 402        /*
 403         * Clear the bar upper 32bit and let guest to assign the new value
 404         */
 405        memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
 406        memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
 407        memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_4, 0, 8);
 408        memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
 409
 410        vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size =
 411                pci_resource_len(pdev, 0);
 412        vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_APERTURE].size =
 413                pci_resource_len(pdev, 2);
 414
 415        memset(vgpu_cfg_space(vgpu) + PCI_ROM_ADDRESS, 0, 4);
 416
 417        /* PM Support */
 418        vgpu->cfg_space.pmcsr_off = 0;
 419        if (vgpu_cfg_space(vgpu)[PCI_STATUS] & PCI_STATUS_CAP_LIST) {
 420                next = vgpu_cfg_space(vgpu)[PCI_CAPABILITY_LIST];
 421                do {
 422                        if (vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_ID] == PCI_CAP_ID_PM) {
 423                                vgpu->cfg_space.pmcsr_off = next + PCI_PM_CTRL;
 424                                break;
 425                        }
 426                        next = vgpu_cfg_space(vgpu)[next + PCI_CAP_LIST_NEXT];
 427                } while (next);
 428        }
 429}
 430
 431/**
 432 * intel_vgpu_reset_cfg_space - reset vGPU configuration space
 433 *
 434 * @vgpu: a vGPU
 435 *
 436 */
 437void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu)
 438{
 439        u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND];
 440        bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] !=
 441                                INTEL_GVT_PCI_CLASS_VGA_OTHER;
 442
 443        if (cmd & PCI_COMMAND_MEMORY) {
 444                trap_gttmmio(vgpu, false);
 445                map_aperture(vgpu, false);
 446        }
 447
 448        /**
 449         * Currently we only do such reset when vGPU is not
 450         * owned by any VM, so we simply restore entire cfg
 451         * space to default value.
 452         */
 453        intel_vgpu_init_cfg_space(vgpu, primary);
 454}
 455