Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0021  * SOFTWARE.
0022  *
0023  * Authors:
0024  *    Zhi Wang <zhi.a.wang@intel.com>
0025  *
0026  * Contributors:
0027  *    Changbin Du <changbin.du@intel.com>
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;      /* protect the data after this field */
0043     u32 version;
0044     u64 cfg_space_size;
0045     u64 cfg_space_offset;   /* offset in the file */
0046     u64 mmio_size;
0047     u64 mmio_offset;    /* offset in the file */
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  * intel_gvt_free_firmware - free GVT firmware
0131  * @gvt: intel gvt device
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  * intel_gvt_load_firmware - load GVT firmware
0195  * @gvt: intel gvt device
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 }