1 1.1 riastrad /* $NetBSD: firmware.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright(c) 2011-2016 Intel Corporation. All rights reserved. 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice (including the next 14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 15 1.1 riastrad * Software. 16 1.1 riastrad * 17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 1.1 riastrad * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 1.1 riastrad * SOFTWARE. 24 1.1 riastrad * 25 1.1 riastrad * Authors: 26 1.1 riastrad * Zhi Wang <zhi.a.wang (at) intel.com> 27 1.1 riastrad * 28 1.1 riastrad * Contributors: 29 1.1 riastrad * Changbin Du <changbin.du (at) intel.com> 30 1.1 riastrad * 31 1.1 riastrad */ 32 1.1 riastrad 33 1.1 riastrad #include <sys/cdefs.h> 34 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: firmware.c,v 1.2 2021/12/18 23:45:31 riastradh Exp $"); 35 1.1 riastrad 36 1.1 riastrad #include <linux/firmware.h> 37 1.1 riastrad #include <linux/crc32.h> 38 1.1 riastrad 39 1.1 riastrad #include "i915_drv.h" 40 1.1 riastrad #include "gvt.h" 41 1.1 riastrad #include "i915_pvinfo.h" 42 1.1 riastrad 43 1.1 riastrad #define FIRMWARE_VERSION (0x0) 44 1.1 riastrad 45 1.1 riastrad struct gvt_firmware_header { 46 1.1 riastrad u64 magic; 47 1.1 riastrad u32 crc32; /* protect the data after this field */ 48 1.1 riastrad u32 version; 49 1.1 riastrad u64 cfg_space_size; 50 1.1 riastrad u64 cfg_space_offset; /* offset in the file */ 51 1.1 riastrad u64 mmio_size; 52 1.1 riastrad u64 mmio_offset; /* offset in the file */ 53 1.1 riastrad unsigned char data[1]; 54 1.1 riastrad }; 55 1.1 riastrad 56 1.1 riastrad #define dev_to_drm_minor(d) dev_get_drvdata((d)) 57 1.1 riastrad 58 1.1 riastrad static ssize_t 59 1.1 riastrad gvt_firmware_read(struct file *filp, struct kobject *kobj, 60 1.1 riastrad struct bin_attribute *attr, char *buf, 61 1.1 riastrad loff_t offset, size_t count) 62 1.1 riastrad { 63 1.1 riastrad memcpy(buf, attr->private + offset, count); 64 1.1 riastrad return count; 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad static struct bin_attribute firmware_attr = { 68 1.1 riastrad .attr = {.name = "gvt_firmware", .mode = (S_IRUSR)}, 69 1.1 riastrad .read = gvt_firmware_read, 70 1.1 riastrad .write = NULL, 71 1.1 riastrad .mmap = NULL, 72 1.1 riastrad }; 73 1.1 riastrad 74 1.1 riastrad static int mmio_snapshot_handler(struct intel_gvt *gvt, u32 offset, void *data) 75 1.1 riastrad { 76 1.1 riastrad struct drm_i915_private *i915 = gvt->dev_priv; 77 1.1 riastrad 78 1.1 riastrad *(u32 *)(data + offset) = intel_uncore_read_notrace(&i915->uncore, 79 1.1 riastrad _MMIO(offset)); 80 1.1 riastrad return 0; 81 1.1 riastrad } 82 1.1 riastrad 83 1.1 riastrad static int expose_firmware_sysfs(struct intel_gvt *gvt) 84 1.1 riastrad { 85 1.1 riastrad struct intel_gvt_device_info *info = &gvt->device_info; 86 1.1 riastrad struct pci_dev *pdev = gvt->dev_priv->drm.pdev; 87 1.1 riastrad struct gvt_firmware_header *h; 88 1.1 riastrad void *firmware; 89 1.1 riastrad void *p; 90 1.1 riastrad unsigned long size, crc32_start; 91 1.1 riastrad int i, ret; 92 1.1 riastrad 93 1.1 riastrad size = sizeof(*h) + info->mmio_size + info->cfg_space_size; 94 1.1 riastrad firmware = vzalloc(size); 95 1.1 riastrad if (!firmware) 96 1.1 riastrad return -ENOMEM; 97 1.1 riastrad 98 1.1 riastrad h = firmware; 99 1.1 riastrad 100 1.1 riastrad h->magic = VGT_MAGIC; 101 1.1 riastrad h->version = FIRMWARE_VERSION; 102 1.1 riastrad h->cfg_space_size = info->cfg_space_size; 103 1.1 riastrad h->cfg_space_offset = offsetof(struct gvt_firmware_header, data); 104 1.1 riastrad h->mmio_size = info->mmio_size; 105 1.1 riastrad h->mmio_offset = h->cfg_space_offset + h->cfg_space_size; 106 1.1 riastrad 107 1.1 riastrad p = firmware + h->cfg_space_offset; 108 1.1 riastrad 109 1.1 riastrad for (i = 0; i < h->cfg_space_size; i += 4) 110 1.1 riastrad pci_read_config_dword(pdev, i, p + i); 111 1.1 riastrad 112 1.1 riastrad memcpy(gvt->firmware.cfg_space, p, info->cfg_space_size); 113 1.1 riastrad 114 1.1 riastrad p = firmware + h->mmio_offset; 115 1.1 riastrad 116 1.1 riastrad /* Take a snapshot of hw mmio registers. */ 117 1.1 riastrad intel_gvt_for_each_tracked_mmio(gvt, mmio_snapshot_handler, p); 118 1.1 riastrad 119 1.1 riastrad memcpy(gvt->firmware.mmio, p, info->mmio_size); 120 1.1 riastrad 121 1.1 riastrad crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4; 122 1.1 riastrad h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start); 123 1.1 riastrad 124 1.1 riastrad firmware_attr.size = size; 125 1.1 riastrad firmware_attr.private = firmware; 126 1.1 riastrad 127 1.1 riastrad ret = device_create_bin_file(&pdev->dev, &firmware_attr); 128 1.1 riastrad if (ret) { 129 1.1 riastrad vfree(firmware); 130 1.1 riastrad return ret; 131 1.1 riastrad } 132 1.1 riastrad return 0; 133 1.1 riastrad } 134 1.1 riastrad 135 1.1 riastrad static void clean_firmware_sysfs(struct intel_gvt *gvt) 136 1.1 riastrad { 137 1.1 riastrad struct pci_dev *pdev = gvt->dev_priv->drm.pdev; 138 1.1 riastrad 139 1.1 riastrad device_remove_bin_file(&pdev->dev, &firmware_attr); 140 1.1 riastrad vfree(firmware_attr.private); 141 1.1 riastrad } 142 1.1 riastrad 143 1.1 riastrad /** 144 1.1 riastrad * intel_gvt_free_firmware - free GVT firmware 145 1.1 riastrad * @gvt: intel gvt device 146 1.1 riastrad * 147 1.1 riastrad */ 148 1.1 riastrad void intel_gvt_free_firmware(struct intel_gvt *gvt) 149 1.1 riastrad { 150 1.1 riastrad if (!gvt->firmware.firmware_loaded) 151 1.1 riastrad clean_firmware_sysfs(gvt); 152 1.1 riastrad 153 1.1 riastrad kfree(gvt->firmware.cfg_space); 154 1.1 riastrad vfree(gvt->firmware.mmio); 155 1.1 riastrad } 156 1.1 riastrad 157 1.1 riastrad static int verify_firmware(struct intel_gvt *gvt, 158 1.1 riastrad const struct firmware *fw) 159 1.1 riastrad { 160 1.1 riastrad struct intel_gvt_device_info *info = &gvt->device_info; 161 1.1 riastrad struct drm_i915_private *dev_priv = gvt->dev_priv; 162 1.1 riastrad struct pci_dev *pdev = dev_priv->drm.pdev; 163 1.1 riastrad struct gvt_firmware_header *h; 164 1.1 riastrad unsigned long id, crc32_start; 165 1.1 riastrad const void *mem; 166 1.1 riastrad const char *item; 167 1.1 riastrad u64 file, request; 168 1.1 riastrad 169 1.1 riastrad h = (struct gvt_firmware_header *)fw->data; 170 1.1 riastrad 171 1.1 riastrad crc32_start = offsetofend(struct gvt_firmware_header, crc32); 172 1.1 riastrad mem = fw->data + crc32_start; 173 1.1 riastrad 174 1.1 riastrad #define VERIFY(s, a, b) do { \ 175 1.1 riastrad item = (s); file = (u64)(a); request = (u64)(b); \ 176 1.1 riastrad if ((a) != (b)) \ 177 1.1 riastrad goto invalid_firmware; \ 178 1.1 riastrad } while (0) 179 1.1 riastrad 180 1.1 riastrad VERIFY("magic number", h->magic, VGT_MAGIC); 181 1.1 riastrad VERIFY("version", h->version, FIRMWARE_VERSION); 182 1.1 riastrad VERIFY("crc32", h->crc32, crc32_le(0, mem, fw->size - crc32_start)); 183 1.1 riastrad VERIFY("cfg space size", h->cfg_space_size, info->cfg_space_size); 184 1.1 riastrad VERIFY("mmio size", h->mmio_size, info->mmio_size); 185 1.1 riastrad 186 1.1 riastrad mem = (fw->data + h->cfg_space_offset); 187 1.1 riastrad 188 1.1 riastrad id = *(u16 *)(mem + PCI_VENDOR_ID); 189 1.1 riastrad VERIFY("vender id", id, pdev->vendor); 190 1.1 riastrad 191 1.1 riastrad id = *(u16 *)(mem + PCI_DEVICE_ID); 192 1.1 riastrad VERIFY("device id", id, pdev->device); 193 1.1 riastrad 194 1.1 riastrad id = *(u8 *)(mem + PCI_REVISION_ID); 195 1.1 riastrad VERIFY("revision id", id, pdev->revision); 196 1.1 riastrad 197 1.1 riastrad #undef VERIFY 198 1.1 riastrad return 0; 199 1.1 riastrad 200 1.1 riastrad invalid_firmware: 201 1.1 riastrad gvt_dbg_core("Invalid firmware: %s [file] 0x%llx [request] 0x%llx\n", 202 1.1 riastrad item, file, request); 203 1.1 riastrad return -EINVAL; 204 1.1 riastrad } 205 1.1 riastrad 206 1.1 riastrad #define GVT_FIRMWARE_PATH "i915/gvt" 207 1.1 riastrad 208 1.1 riastrad /** 209 1.1 riastrad * intel_gvt_load_firmware - load GVT firmware 210 1.1 riastrad * @gvt: intel gvt device 211 1.1 riastrad * 212 1.1 riastrad */ 213 1.1 riastrad int intel_gvt_load_firmware(struct intel_gvt *gvt) 214 1.1 riastrad { 215 1.1 riastrad struct intel_gvt_device_info *info = &gvt->device_info; 216 1.1 riastrad struct drm_i915_private *dev_priv = gvt->dev_priv; 217 1.1 riastrad struct pci_dev *pdev = dev_priv->drm.pdev; 218 1.1 riastrad struct intel_gvt_firmware *firmware = &gvt->firmware; 219 1.1 riastrad struct gvt_firmware_header *h; 220 1.1 riastrad const struct firmware *fw; 221 1.1 riastrad char *path; 222 1.1 riastrad void *mem; 223 1.1 riastrad int ret; 224 1.1 riastrad 225 1.1 riastrad path = kmalloc(PATH_MAX, GFP_KERNEL); 226 1.1 riastrad if (!path) 227 1.1 riastrad return -ENOMEM; 228 1.1 riastrad 229 1.1 riastrad mem = kmalloc(info->cfg_space_size, GFP_KERNEL); 230 1.1 riastrad if (!mem) { 231 1.1 riastrad kfree(path); 232 1.1 riastrad return -ENOMEM; 233 1.1 riastrad } 234 1.1 riastrad 235 1.1 riastrad firmware->cfg_space = mem; 236 1.1 riastrad 237 1.1 riastrad mem = vmalloc(info->mmio_size); 238 1.1 riastrad if (!mem) { 239 1.1 riastrad kfree(path); 240 1.1 riastrad kfree(firmware->cfg_space); 241 1.1 riastrad return -ENOMEM; 242 1.1 riastrad } 243 1.1 riastrad 244 1.1 riastrad firmware->mmio = mem; 245 1.1 riastrad 246 1.1 riastrad sprintf(path, "%s/vid_0x%04x_did_0x%04x_rid_0x%02x.golden_hw_state", 247 1.1 riastrad GVT_FIRMWARE_PATH, pdev->vendor, pdev->device, 248 1.1 riastrad pdev->revision); 249 1.1 riastrad 250 1.1 riastrad gvt_dbg_core("request hw state firmware %s...\n", path); 251 1.1 riastrad 252 1.1 riastrad ret = request_firmware(&fw, path, &dev_priv->drm.pdev->dev); 253 1.1 riastrad kfree(path); 254 1.1 riastrad 255 1.1 riastrad if (ret) 256 1.1 riastrad goto expose_firmware; 257 1.1 riastrad 258 1.1 riastrad gvt_dbg_core("success.\n"); 259 1.1 riastrad 260 1.1 riastrad ret = verify_firmware(gvt, fw); 261 1.1 riastrad if (ret) 262 1.1 riastrad goto out_free_fw; 263 1.1 riastrad 264 1.1 riastrad gvt_dbg_core("verified.\n"); 265 1.1 riastrad 266 1.1 riastrad h = (struct gvt_firmware_header *)fw->data; 267 1.1 riastrad 268 1.1 riastrad memcpy(firmware->cfg_space, fw->data + h->cfg_space_offset, 269 1.1 riastrad h->cfg_space_size); 270 1.1 riastrad memcpy(firmware->mmio, fw->data + h->mmio_offset, 271 1.1 riastrad h->mmio_size); 272 1.1 riastrad 273 1.1 riastrad release_firmware(fw); 274 1.1 riastrad firmware->firmware_loaded = true; 275 1.1 riastrad return 0; 276 1.1 riastrad 277 1.1 riastrad out_free_fw: 278 1.1 riastrad release_firmware(fw); 279 1.1 riastrad expose_firmware: 280 1.1 riastrad expose_firmware_sysfs(gvt); 281 1.1 riastrad return 0; 282 1.1 riastrad } 283