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 * Kevin Tian <kevin.tian@intel.com> 25 * Eddie Dong <eddie.dong@intel.com> 26 * Zhiyuan Lv <zhiyuan.lv@intel.com> 27 * 28 * Contributors: 29 * Min He <min.he@intel.com> 30 * Tina Zhang <tina.zhang@intel.com> 31 * Pei Zhang <pei.zhang@intel.com> 32 * Niu Bing <bing.niu@intel.com> 33 * Ping Gao <ping.a.gao@intel.com> 34 * Zhi Wang <zhi.a.wang@intel.com> 35 * 36 37 */ 38 39 #include "i915_drv.h" 40 41 /* Register contains RO bits */ 42 #define F_RO (1 << 0) 43 /* Register contains graphics address */ 44 #define F_GMADR (1 << 1) 45 /* Mode mask registers with high 16 bits as the mask bits */ 46 #define F_MODE_MASK (1 << 2) 47 /* This reg can be accessed by GPU commands */ 48 #define F_CMD_ACCESS (1 << 3) 49 /* This reg has been accessed by a VM */ 50 #define F_ACCESSED (1 << 4) 51 /* This reg has been accessed through GPU commands */ 52 #define F_CMD_ACCESSED (1 << 5) 53 /* This reg could be accessed by unaligned address */ 54 #define F_UNALIGN (1 << 6) 55 56 unsigned long intel_gvt_get_device_type(struct intel_gvt *gvt) 57 { 58 if (IS_BROADWELL(gvt->dev_priv)) 59 return D_BDW; 60 else if (IS_SKYLAKE(gvt->dev_priv)) 61 return D_SKL; 62 63 return 0; 64 } 65 66 bool intel_gvt_match_device(struct intel_gvt *gvt, 67 unsigned long device) 68 { 69 return intel_gvt_get_device_type(gvt) & device; 70 } 71 72 static int new_mmio_info(struct intel_gvt *gvt, 73 u32 offset, u32 flags, u32 size, 74 u32 addr_mask, u32 ro_mask, u32 device, 75 void *read, void *write) 76 { 77 struct intel_gvt_mmio_info *info, *p; 78 u32 start, end, i; 79 80 if (!intel_gvt_match_device(gvt, device)) 81 return 0; 82 83 if (WARN_ON(!IS_ALIGNED(offset, 4))) 84 return -EINVAL; 85 86 start = offset; 87 end = offset + size; 88 89 for (i = start; i < end; i += 4) { 90 info = kzalloc(sizeof(*info), GFP_KERNEL); 91 if (!info) 92 return -ENOMEM; 93 94 info->offset = i; 95 p = intel_gvt_find_mmio_info(gvt, info->offset); 96 if (p) 97 gvt_err("dup mmio definition offset %x\n", 98 info->offset); 99 info->size = size; 100 info->length = (i + 4) < end ? 4 : (end - i); 101 info->addr_mask = addr_mask; 102 info->device = device; 103 info->read = read; 104 info->write = write; 105 gvt->mmio.mmio_attribute[info->offset / 4] = flags; 106 INIT_HLIST_NODE(&info->node); 107 hash_add(gvt->mmio.mmio_info_table, &info->node, info->offset); 108 } 109 return 0; 110 } 111 112 #define MMIO_F(reg, s, f, am, rm, d, r, w) do { \ 113 ret = new_mmio_info(gvt, INTEL_GVT_MMIO_OFFSET(reg), \ 114 f, s, am, rm, d, r, w); \ 115 if (ret) \ 116 return ret; \ 117 } while (0) 118 119 #define MMIO_D(reg, d) \ 120 MMIO_F(reg, 4, 0, 0, 0, d, NULL, NULL) 121 122 #define MMIO_DH(reg, d, r, w) \ 123 MMIO_F(reg, 4, 0, 0, 0, d, r, w) 124 125 #define MMIO_DFH(reg, d, f, r, w) \ 126 MMIO_F(reg, 4, f, 0, 0, d, r, w) 127 128 #define MMIO_GM(reg, d, r, w) \ 129 MMIO_F(reg, 4, F_GMADR, 0xFFFFF000, 0, d, r, w) 130 131 #define MMIO_RO(reg, d, f, rm, r, w) \ 132 MMIO_F(reg, 4, F_RO | f, 0, rm, d, r, w) 133 134 #define MMIO_RING_F(prefix, s, f, am, rm, d, r, w) do { \ 135 MMIO_F(prefix(RENDER_RING_BASE), s, f, am, rm, d, r, w); \ 136 MMIO_F(prefix(BLT_RING_BASE), s, f, am, rm, d, r, w); \ 137 MMIO_F(prefix(GEN6_BSD_RING_BASE), s, f, am, rm, d, r, w); \ 138 MMIO_F(prefix(VEBOX_RING_BASE), s, f, am, rm, d, r, w); \ 139 } while (0) 140 141 #define MMIO_RING_D(prefix, d) \ 142 MMIO_RING_F(prefix, 4, 0, 0, 0, d, NULL, NULL) 143 144 #define MMIO_RING_DFH(prefix, d, f, r, w) \ 145 MMIO_RING_F(prefix, 4, f, 0, 0, d, r, w) 146 147 #define MMIO_RING_GM(prefix, d, r, w) \ 148 MMIO_RING_F(prefix, 4, F_GMADR, 0xFFFF0000, 0, d, r, w) 149 150 #define MMIO_RING_RO(prefix, d, f, rm, r, w) \ 151 MMIO_RING_F(prefix, 4, F_RO | f, 0, rm, d, r, w) 152 153 static int init_generic_mmio_info(struct intel_gvt *gvt) 154 { 155 int ret; 156 157 MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL); 158 return 0; 159 } 160 161 static int init_broadwell_mmio_info(struct intel_gvt *gvt) 162 { 163 int ret; 164 165 MMIO_F(0, 0, 0, 0, 0, D_ALL, NULL, NULL); 166 return 0; 167 } 168 169 /** 170 * intel_gvt_find_mmio_info - find MMIO information entry by aligned offset 171 * @gvt: GVT device 172 * @offset: register offset 173 * 174 * This function is used to find the MMIO information entry from hash table 175 * 176 * Returns: 177 * pointer to MMIO information entry, NULL if not exists 178 */ 179 struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt, 180 unsigned int offset) 181 { 182 struct intel_gvt_mmio_info *e; 183 184 WARN_ON(!IS_ALIGNED(offset, 4)); 185 186 hash_for_each_possible(gvt->mmio.mmio_info_table, e, node, offset) { 187 if (e->offset == offset) 188 return e; 189 } 190 return NULL; 191 } 192 193 /** 194 * intel_gvt_clean_mmio_info - clean up MMIO information table for GVT device 195 * @gvt: GVT device 196 * 197 * This function is called at the driver unloading stage, to clean up the MMIO 198 * information table of GVT device 199 * 200 */ 201 void intel_gvt_clean_mmio_info(struct intel_gvt *gvt) 202 { 203 struct hlist_node *tmp; 204 struct intel_gvt_mmio_info *e; 205 int i; 206 207 hash_for_each_safe(gvt->mmio.mmio_info_table, i, tmp, e, node) 208 kfree(e); 209 210 vfree(gvt->mmio.mmio_attribute); 211 gvt->mmio.mmio_attribute = NULL; 212 } 213 214 /** 215 * intel_gvt_setup_mmio_info - setup MMIO information table for GVT device 216 * @gvt: GVT device 217 * 218 * This function is called at the initialization stage, to setup the MMIO 219 * information table for GVT device 220 * 221 * Returns: 222 * zero on success, negative if failed. 223 */ 224 int intel_gvt_setup_mmio_info(struct intel_gvt *gvt) 225 { 226 struct intel_gvt_device_info *info = &gvt->device_info; 227 struct drm_i915_private *dev_priv = gvt->dev_priv; 228 int ret; 229 230 gvt->mmio.mmio_attribute = vzalloc(info->mmio_size); 231 if (!gvt->mmio.mmio_attribute) 232 return -ENOMEM; 233 234 ret = init_generic_mmio_info(gvt); 235 if (ret) 236 goto err; 237 238 if (IS_BROADWELL(dev_priv)) { 239 ret = init_broadwell_mmio_info(gvt); 240 if (ret) 241 goto err; 242 } 243 return 0; 244 err: 245 intel_gvt_clean_mmio_info(gvt); 246 return ret; 247 } 248