aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangbin Du <changbin.du@intel.com>2017-03-06 04:08:30 -0500
committerZhenyu Wang <zhenyuw@linux.intel.com>2017-03-06 04:29:02 -0500
commitc2e04fdab33181b53b5a2f9662b7b607b720f79f (patch)
tree14319135e5d499e622869243efda7f67ad239ba8
parent8f1117abb408808af9cc4c948925c726bec4755a (diff)
drm/i915/gvt: protect RO and Rsvd bits of virtual vgpu configuration space
Per PCI specification, Configuration Register has different types (RO, RW, RW1C, Rsvd). For RO Register bits are read-only and cannot be altered by software. For RW1C Register bits indicate status when read. A Set bit indicates a status event which is Cleared by writing a 1b. Writing a 0b to RW1C bits has no effect. Reserved Register is for future implementations, and they are read-only and must return zero when read. Current vGPU configuration write emulation just copy the value as it is. So we haven't emulated RO, RW1C and Rsvd Registers correctly. This patch is following the Spec to correct emulation logic. We add a function vgpu_cfg_mem_write to wrap the access to vGPU configuration memory. The write function uses a RW Register bitmap to avoid RO bits be overwritten, and emulate RW1C behavior for the particular status Register. v2: new = src[i] --> new = src[i] & mask (zhenyu) Signed-off-by: Changbin Du <changbin.du@intel.com> Cc: Xiaoguang Chen <xiaoguang.chen@intel.com> Cc: Zhiyuan Lv <zhiyuan.lv@intel.com> Cc: Min He <min.he@intel.com> Reviewed-by: Zhenyu Wang <zhenyuw@linux.intel.com> Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
-rw-r--r--drivers/gpu/drm/i915/gvt/cfg_space.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c
index a77e050b85a3..b7d7721e72fa 100644
--- a/drivers/gpu/drm/i915/gvt/cfg_space.c
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -41,6 +41,54 @@ enum {
41 INTEL_GVT_PCI_BAR_MAX, 41 INTEL_GVT_PCI_BAR_MAX,
42}; 42};
43 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 *
60 * Use this function to write virtual cfg space memory.
61 * For standard cfg space, only RW bits can be changed,
62 * and we emulates the RW1C behavior of PCI_STATUS register.
63 */
64static void vgpu_pci_cfg_mem_write(struct intel_vgpu *vgpu, unsigned int off,
65 u8 *src, unsigned int bytes)
66{
67 u8 *cfg_base = vgpu_cfg_space(vgpu);
68 u8 mask, new, old;
69 int i = 0;
70
71 for (; i < bytes && (off + i < sizeof(pci_cfg_space_rw_bmp)); i++) {
72 mask = pci_cfg_space_rw_bmp[off + i];
73 old = cfg_base[off + i];
74 new = src[i] & mask;
75
76 /**
77 * The PCI_STATUS high byte has RW1C bits, here
78 * emulates clear by writing 1 for these bits.
79 * Writing a 0b to RW1C bits has no effect.
80 */
81 if (off + i == PCI_STATUS + 1)
82 new = (~new & old) & mask;
83
84 cfg_base[off + i] = (old & ~mask) | new;
85 }
86
87 /* For other configuration space directly copy as it is. */
88 if (i < bytes)
89 memcpy(cfg_base + off + i, src + i, bytes - i);
90}
91
44/** 92/**
45 * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read 93 * intel_vgpu_emulate_cfg_read - emulate vGPU configuration space read
46 * 94 *
@@ -123,7 +171,7 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu,
123 u8 changed = old ^ new; 171 u8 changed = old ^ new;
124 int ret; 172 int ret;
125 173
126 memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 174 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
127 if (!(changed & PCI_COMMAND_MEMORY)) 175 if (!(changed & PCI_COMMAND_MEMORY))
128 return 0; 176 return 0;
129 177
@@ -277,10 +325,10 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
277 if (ret) 325 if (ret)
278 return ret; 326 return ret;
279 327
280 memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 328 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
281 break; 329 break;
282 default: 330 default:
283 memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); 331 vgpu_pci_cfg_mem_write(vgpu, offset, p_data, bytes);
284 break; 332 break;
285 } 333 }
286 return 0; 334 return 0;