1 // SPDX-License-Identifier: GPL-2.0-only
3 * VFIO PCI Intel Graphics support
5 * Copyright (C) 2016 Red Hat, Inc. All rights reserved.
6 * Author: Alex Williamson <alex.williamson@redhat.com>
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.
14 #include <linux/pci.h>
15 #include <linux/uaccess.h>
16 #include <linux/vfio.h>
18 #include "vfio_pci_private.h"
20 #define OPREGION_SIGNATURE "IntelGraphicsMem"
21 #define OPREGION_SIZE (8 * 1024)
22 #define OPREGION_PCI_ADDR 0xfc
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
)
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
;
31 if (pos
>= vdev
->region
[i
].size
|| iswrite
)
34 count
= min(count
, (size_t)(vdev
->region
[i
].size
- pos
));
36 if (copy_to_user(buf
, base
+ pos
, count
))
44 static void vfio_pci_igd_release(struct vfio_pci_device
*vdev
,
45 struct vfio_pci_region
*region
)
47 memunmap(region
->data
);
50 static const struct vfio_pci_regops vfio_pci_igd_regops
= {
51 .rw
= vfio_pci_igd_rw
,
52 .release
= vfio_pci_igd_release
,
55 static int vfio_pci_igd_opregion_init(struct vfio_pci_device
*vdev
)
57 __le32
*dwordp
= (__le32
*)(vdev
->vconfig
+ OPREGION_PCI_ADDR
);
62 ret
= pci_read_config_dword(vdev
->pdev
, OPREGION_PCI_ADDR
, &addr
);
66 if (!addr
|| !(~addr
))
69 base
= memremap(addr
, OPREGION_SIZE
, MEMREMAP_WB
);
73 if (memcmp(base
, OPREGION_SIGNATURE
, 16)) {
78 size
= le32_to_cpu(*(__le32
*)(base
+ 16));
84 size
*= 1024; /* In KB */
86 if (size
!= OPREGION_SIZE
) {
88 base
= memremap(addr
, size
, MEMREMAP_WB
);
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
);
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);
110 static size_t vfio_pci_igd_cfg_rw(struct vfio_pci_device
*vdev
,
111 char __user
*buf
, size_t count
, loff_t
*ppos
,
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
;
120 if (pos
>= vdev
->region
[i
].size
|| iswrite
)
123 size
= count
= min(count
, (size_t)(vdev
->region
[i
].size
- pos
));
125 if ((pos
& 1) && size
) {
128 ret
= pci_user_read_config_byte(pdev
, pos
, &val
);
130 return pcibios_err_to_errno(ret
);
132 if (copy_to_user(buf
+ count
- size
, &val
, 1))
139 if ((pos
& 3) && size
> 2) {
142 ret
= pci_user_read_config_word(pdev
, pos
, &val
);
144 return pcibios_err_to_errno(ret
);
146 val
= cpu_to_le16(val
);
147 if (copy_to_user(buf
+ count
- size
, &val
, 2))
157 ret
= pci_user_read_config_dword(pdev
, pos
, &val
);
159 return pcibios_err_to_errno(ret
);
161 val
= cpu_to_le32(val
);
162 if (copy_to_user(buf
+ count
- size
, &val
, 4))
172 ret
= pci_user_read_config_word(pdev
, pos
, &val
);
174 return pcibios_err_to_errno(ret
);
176 val
= cpu_to_le16(val
);
177 if (copy_to_user(buf
+ count
- size
, &val
, 2))
187 ret
= pci_user_read_config_byte(pdev
, pos
, &val
);
189 return pcibios_err_to_errno(ret
);
191 if (copy_to_user(buf
+ count
- size
, &val
, 1))
203 static void vfio_pci_igd_cfg_release(struct vfio_pci_device
*vdev
,
204 struct vfio_pci_region
*region
)
206 struct pci_dev
*pdev
= region
->data
;
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
,
216 static int vfio_pci_igd_cfg_init(struct vfio_pci_device
*vdev
)
218 struct pci_dev
*host_bridge
, *lpc_bridge
;
221 host_bridge
= pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
225 if (host_bridge
->vendor
!= PCI_VENDOR_ID_INTEL
||
226 host_bridge
->class != (PCI_CLASS_BRIDGE_HOST
<< 8)) {
227 pci_dev_put(host_bridge
);
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
);
237 pci_dev_put(host_bridge
);
241 lpc_bridge
= pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x1f, 0));
245 if (lpc_bridge
->vendor
!= PCI_VENDOR_ID_INTEL
||
246 lpc_bridge
->class != (PCI_CLASS_BRIDGE_ISA
<< 8)) {
247 pci_dev_put(lpc_bridge
);
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
);
257 pci_dev_put(lpc_bridge
);
264 int vfio_pci_igd_init(struct vfio_pci_device
*vdev
)
268 ret
= vfio_pci_igd_opregion_init(vdev
);
272 ret
= vfio_pci_igd_cfg_init(vdev
);