Merge tag 'nfs-rdma-for-5.3-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[linux-2.6-microblaze.git] / drivers / vfio / pci / vfio_pci_igd.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * VFIO PCI Intel Graphics support
4  *
5  * Copyright (C) 2016 Red Hat, Inc.  All rights reserved.
6  *      Author: Alex Williamson <alex.williamson@redhat.com>
7  *
8  * Register a device specific region through which to provide read-only
9  * access to the Intel IGD opregion.  The register defining the opregion
10  * address is also virtualized to prevent user modification.
11  */
12
13 #include <linux/io.h>
14 #include <linux/pci.h>
15 #include <linux/uaccess.h>
16 #include <linux/vfio.h>
17
18 #include "vfio_pci_private.h"
19
20 #define OPREGION_SIGNATURE      "IntelGraphicsMem"
21 #define OPREGION_SIZE           (8 * 1024)
22 #define OPREGION_PCI_ADDR       0xfc
23
24 static size_t vfio_pci_igd_rw(struct vfio_pci_device *vdev, char __user *buf,
25                               size_t count, loff_t *ppos, bool iswrite)
26 {
27         unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
28         void *base = vdev->region[i].data;
29         loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
30
31         if (pos >= vdev->region[i].size || iswrite)
32                 return -EINVAL;
33
34         count = min(count, (size_t)(vdev->region[i].size - pos));
35
36         if (copy_to_user(buf, base + pos, count))
37                 return -EFAULT;
38
39         *ppos += count;
40
41         return count;
42 }
43
44 static void vfio_pci_igd_release(struct vfio_pci_device *vdev,
45                                  struct vfio_pci_region *region)
46 {
47         memunmap(region->data);
48 }
49
50 static const struct vfio_pci_regops vfio_pci_igd_regops = {
51         .rw             = vfio_pci_igd_rw,
52         .release        = vfio_pci_igd_release,
53 };
54
55 static int vfio_pci_igd_opregion_init(struct vfio_pci_device *vdev)
56 {
57         __le32 *dwordp = (__le32 *)(vdev->vconfig + OPREGION_PCI_ADDR);
58         u32 addr, size;
59         void *base;
60         int ret;
61
62         ret = pci_read_config_dword(vdev->pdev, OPREGION_PCI_ADDR, &addr);
63         if (ret)
64                 return ret;
65
66         if (!addr || !(~addr))
67                 return -ENODEV;
68
69         base = memremap(addr, OPREGION_SIZE, MEMREMAP_WB);
70         if (!base)
71                 return -ENOMEM;
72
73         if (memcmp(base, OPREGION_SIGNATURE, 16)) {
74                 memunmap(base);
75                 return -EINVAL;
76         }
77
78         size = le32_to_cpu(*(__le32 *)(base + 16));
79         if (!size) {
80                 memunmap(base);
81                 return -EINVAL;
82         }
83
84         size *= 1024; /* In KB */
85
86         if (size != OPREGION_SIZE) {
87                 memunmap(base);
88                 base = memremap(addr, size, MEMREMAP_WB);
89                 if (!base)
90                         return -ENOMEM;
91         }
92
93         ret = vfio_pci_register_dev_region(vdev,
94                 PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
95                 VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
96                 &vfio_pci_igd_regops, size, VFIO_REGION_INFO_FLAG_READ, base);
97         if (ret) {
98                 memunmap(base);
99                 return ret;
100         }
101
102         /* Fill vconfig with the hw value and virtualize register */
103         *dwordp = cpu_to_le32(addr);
104         memset(vdev->pci_config_map + OPREGION_PCI_ADDR,
105                PCI_CAP_ID_INVALID_VIRT, 4);
106
107         return ret;
108 }
109
110 static size_t vfio_pci_igd_cfg_rw(struct vfio_pci_device *vdev,
111                                   char __user *buf, size_t count, loff_t *ppos,
112                                   bool iswrite)
113 {
114         unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS;
115         struct pci_dev *pdev = vdev->region[i].data;
116         loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
117         size_t size;
118         int ret;
119
120         if (pos >= vdev->region[i].size || iswrite)
121                 return -EINVAL;
122
123         size = count = min(count, (size_t)(vdev->region[i].size - pos));
124
125         if ((pos & 1) && size) {
126                 u8 val;
127
128                 ret = pci_user_read_config_byte(pdev, pos, &val);
129                 if (ret)
130                         return pcibios_err_to_errno(ret);
131
132                 if (copy_to_user(buf + count - size, &val, 1))
133                         return -EFAULT;
134
135                 pos++;
136                 size--;
137         }
138
139         if ((pos & 3) && size > 2) {
140                 u16 val;
141
142                 ret = pci_user_read_config_word(pdev, pos, &val);
143                 if (ret)
144                         return pcibios_err_to_errno(ret);
145
146                 val = cpu_to_le16(val);
147                 if (copy_to_user(buf + count - size, &val, 2))
148                         return -EFAULT;
149
150                 pos += 2;
151                 size -= 2;
152         }
153
154         while (size > 3) {
155                 u32 val;
156
157                 ret = pci_user_read_config_dword(pdev, pos, &val);
158                 if (ret)
159                         return pcibios_err_to_errno(ret);
160
161                 val = cpu_to_le32(val);
162                 if (copy_to_user(buf + count - size, &val, 4))
163                         return -EFAULT;
164
165                 pos += 4;
166                 size -= 4;
167         }
168
169         while (size >= 2) {
170                 u16 val;
171
172                 ret = pci_user_read_config_word(pdev, pos, &val);
173                 if (ret)
174                         return pcibios_err_to_errno(ret);
175
176                 val = cpu_to_le16(val);
177                 if (copy_to_user(buf + count - size, &val, 2))
178                         return -EFAULT;
179
180                 pos += 2;
181                 size -= 2;
182         }
183
184         while (size) {
185                 u8 val;
186
187                 ret = pci_user_read_config_byte(pdev, pos, &val);
188                 if (ret)
189                         return pcibios_err_to_errno(ret);
190
191                 if (copy_to_user(buf + count - size, &val, 1))
192                         return -EFAULT;
193
194                 pos++;
195                 size--;
196         }
197
198         *ppos += count;
199
200         return count;
201 }
202
203 static void vfio_pci_igd_cfg_release(struct vfio_pci_device *vdev,
204                                      struct vfio_pci_region *region)
205 {
206         struct pci_dev *pdev = region->data;
207
208         pci_dev_put(pdev);
209 }
210
211 static const struct vfio_pci_regops vfio_pci_igd_cfg_regops = {
212         .rw             = vfio_pci_igd_cfg_rw,
213         .release        = vfio_pci_igd_cfg_release,
214 };
215
216 static int vfio_pci_igd_cfg_init(struct vfio_pci_device *vdev)
217 {
218         struct pci_dev *host_bridge, *lpc_bridge;
219         int ret;
220
221         host_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
222         if (!host_bridge)
223                 return -ENODEV;
224
225         if (host_bridge->vendor != PCI_VENDOR_ID_INTEL ||
226             host_bridge->class != (PCI_CLASS_BRIDGE_HOST << 8)) {
227                 pci_dev_put(host_bridge);
228                 return -EINVAL;
229         }
230
231         ret = vfio_pci_register_dev_region(vdev,
232                 PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
233                 VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG,
234                 &vfio_pci_igd_cfg_regops, host_bridge->cfg_size,
235                 VFIO_REGION_INFO_FLAG_READ, host_bridge);
236         if (ret) {
237                 pci_dev_put(host_bridge);
238                 return ret;
239         }
240
241         lpc_bridge = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x1f, 0));
242         if (!lpc_bridge)
243                 return -ENODEV;
244
245         if (lpc_bridge->vendor != PCI_VENDOR_ID_INTEL ||
246             lpc_bridge->class != (PCI_CLASS_BRIDGE_ISA << 8)) {
247                 pci_dev_put(lpc_bridge);
248                 return -EINVAL;
249         }
250
251         ret = vfio_pci_register_dev_region(vdev,
252                 PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
253                 VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG,
254                 &vfio_pci_igd_cfg_regops, lpc_bridge->cfg_size,
255                 VFIO_REGION_INFO_FLAG_READ, lpc_bridge);
256         if (ret) {
257                 pci_dev_put(lpc_bridge);
258                 return ret;
259         }
260
261         return 0;
262 }
263
264 int vfio_pci_igd_init(struct vfio_pci_device *vdev)
265 {
266         int ret;
267
268         ret = vfio_pci_igd_opregion_init(vdev);
269         if (ret)
270                 return ret;
271
272         ret = vfio_pci_igd_cfg_init(vdev);
273         if (ret)
274                 return ret;
275
276         return 0;
277 }