0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/firmware.h>
0032 #include <linux/crc32.h>
0033
0034 #include "i915_drv.h"
0035 #include "gvt.h"
0036 #include "i915_pvinfo.h"
0037
0038 #define FIRMWARE_VERSION (0x0)
0039
0040 struct gvt_firmware_header {
0041 u64 magic;
0042 u32 crc32;
0043 u32 version;
0044 u64 cfg_space_size;
0045 u64 cfg_space_offset;
0046 u64 mmio_size;
0047 u64 mmio_offset;
0048 unsigned char data[1];
0049 };
0050
0051 #define dev_to_drm_minor(d) dev_get_drvdata((d))
0052
0053 static ssize_t
0054 gvt_firmware_read(struct file *filp, struct kobject *kobj,
0055 struct bin_attribute *attr, char *buf,
0056 loff_t offset, size_t count)
0057 {
0058 memcpy(buf, attr->private + offset, count);
0059 return count;
0060 }
0061
0062 static struct bin_attribute firmware_attr = {
0063 .attr = {.name = "gvt_firmware", .mode = (S_IRUSR)},
0064 .read = gvt_firmware_read,
0065 .write = NULL,
0066 .mmap = NULL,
0067 };
0068
0069 static int expose_firmware_sysfs(struct intel_gvt *gvt)
0070 {
0071 struct intel_gvt_device_info *info = &gvt->device_info;
0072 struct drm_i915_private *i915 = gvt->gt->i915;
0073 struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
0074 struct gvt_firmware_header *h;
0075 void *firmware;
0076 void *p;
0077 unsigned long size, crc32_start;
0078 int ret;
0079
0080 size = sizeof(*h) + info->mmio_size + info->cfg_space_size;
0081 firmware = vzalloc(size);
0082 if (!firmware)
0083 return -ENOMEM;
0084
0085 h = firmware;
0086
0087 h->magic = VGT_MAGIC;
0088 h->version = FIRMWARE_VERSION;
0089 h->cfg_space_size = info->cfg_space_size;
0090 h->cfg_space_offset = offsetof(struct gvt_firmware_header, data);
0091 h->mmio_size = info->mmio_size;
0092 h->mmio_offset = h->cfg_space_offset + h->cfg_space_size;
0093
0094 p = firmware + h->cfg_space_offset;
0095
0096 memcpy(gvt->firmware.cfg_space, i915->vgpu.initial_cfg_space,
0097 info->cfg_space_size);
0098 memcpy(p, gvt->firmware.cfg_space, info->cfg_space_size);
0099
0100 p = firmware + h->mmio_offset;
0101
0102 memcpy(gvt->firmware.mmio, i915->vgpu.initial_mmio,
0103 info->mmio_size);
0104
0105 memcpy(p, gvt->firmware.mmio, info->mmio_size);
0106
0107 crc32_start = offsetof(struct gvt_firmware_header, crc32) + 4;
0108 h->crc32 = crc32_le(0, firmware + crc32_start, size - crc32_start);
0109
0110 firmware_attr.size = size;
0111 firmware_attr.private = firmware;
0112
0113 ret = device_create_bin_file(&pdev->dev, &firmware_attr);
0114 if (ret) {
0115 vfree(firmware);
0116 return ret;
0117 }
0118 return 0;
0119 }
0120
0121 static void clean_firmware_sysfs(struct intel_gvt *gvt)
0122 {
0123 struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
0124
0125 device_remove_bin_file(&pdev->dev, &firmware_attr);
0126 vfree(firmware_attr.private);
0127 }
0128
0129
0130
0131
0132
0133
0134 void intel_gvt_free_firmware(struct intel_gvt *gvt)
0135 {
0136 if (!gvt->firmware.firmware_loaded)
0137 clean_firmware_sysfs(gvt);
0138
0139 kfree(gvt->firmware.cfg_space);
0140 vfree(gvt->firmware.mmio);
0141 }
0142
0143 static int verify_firmware(struct intel_gvt *gvt,
0144 const struct firmware *fw)
0145 {
0146 struct intel_gvt_device_info *info = &gvt->device_info;
0147 struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
0148 struct gvt_firmware_header *h;
0149 unsigned long id, crc32_start;
0150 const void *mem;
0151 const char *item;
0152 u64 file, request;
0153
0154 h = (struct gvt_firmware_header *)fw->data;
0155
0156 crc32_start = offsetofend(struct gvt_firmware_header, crc32);
0157 mem = fw->data + crc32_start;
0158
0159 #define VERIFY(s, a, b) do { \
0160 item = (s); file = (u64)(a); request = (u64)(b); \
0161 if ((a) != (b)) \
0162 goto invalid_firmware; \
0163 } while (0)
0164
0165 VERIFY("magic number", h->magic, VGT_MAGIC);
0166 VERIFY("version", h->version, FIRMWARE_VERSION);
0167 VERIFY("crc32", h->crc32, crc32_le(0, mem, fw->size - crc32_start));
0168 VERIFY("cfg space size", h->cfg_space_size, info->cfg_space_size);
0169 VERIFY("mmio size", h->mmio_size, info->mmio_size);
0170
0171 mem = (fw->data + h->cfg_space_offset);
0172
0173 id = *(u16 *)(mem + PCI_VENDOR_ID);
0174 VERIFY("vender id", id, pdev->vendor);
0175
0176 id = *(u16 *)(mem + PCI_DEVICE_ID);
0177 VERIFY("device id", id, pdev->device);
0178
0179 id = *(u8 *)(mem + PCI_REVISION_ID);
0180 VERIFY("revision id", id, pdev->revision);
0181
0182 #undef VERIFY
0183 return 0;
0184
0185 invalid_firmware:
0186 gvt_dbg_core("Invalid firmware: %s [file] 0x%llx [request] 0x%llx\n",
0187 item, file, request);
0188 return -EINVAL;
0189 }
0190
0191 #define GVT_FIRMWARE_PATH "i915/gvt"
0192
0193
0194
0195
0196
0197
0198 int intel_gvt_load_firmware(struct intel_gvt *gvt)
0199 {
0200 struct intel_gvt_device_info *info = &gvt->device_info;
0201 struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
0202 struct intel_gvt_firmware *firmware = &gvt->firmware;
0203 struct gvt_firmware_header *h;
0204 const struct firmware *fw;
0205 char *path;
0206 void *mem;
0207 int ret;
0208
0209 path = kmalloc(PATH_MAX, GFP_KERNEL);
0210 if (!path)
0211 return -ENOMEM;
0212
0213 mem = kmalloc(info->cfg_space_size, GFP_KERNEL);
0214 if (!mem) {
0215 kfree(path);
0216 return -ENOMEM;
0217 }
0218
0219 firmware->cfg_space = mem;
0220
0221 mem = vmalloc(info->mmio_size);
0222 if (!mem) {
0223 kfree(path);
0224 kfree(firmware->cfg_space);
0225 return -ENOMEM;
0226 }
0227
0228 firmware->mmio = mem;
0229
0230 sprintf(path, "%s/vid_0x%04x_did_0x%04x_rid_0x%02x.golden_hw_state",
0231 GVT_FIRMWARE_PATH, pdev->vendor, pdev->device,
0232 pdev->revision);
0233
0234 gvt_dbg_core("request hw state firmware %s...\n", path);
0235
0236 ret = request_firmware(&fw, path, gvt->gt->i915->drm.dev);
0237 kfree(path);
0238
0239 if (ret)
0240 goto expose_firmware;
0241
0242 gvt_dbg_core("success.\n");
0243
0244 ret = verify_firmware(gvt, fw);
0245 if (ret)
0246 goto out_free_fw;
0247
0248 gvt_dbg_core("verified.\n");
0249
0250 h = (struct gvt_firmware_header *)fw->data;
0251
0252 memcpy(firmware->cfg_space, fw->data + h->cfg_space_offset,
0253 h->cfg_space_size);
0254 memcpy(firmware->mmio, fw->data + h->mmio_offset,
0255 h->mmio_size);
0256
0257 release_firmware(fw);
0258 firmware->firmware_loaded = true;
0259 return 0;
0260
0261 out_free_fw:
0262 release_firmware(fw);
0263 expose_firmware:
0264 expose_firmware_sysfs(gvt);
0265 return 0;
0266 }