2 * VFIO PCI Intel Graphics support
4 * Copyright (C) 2016 Red Hat, Inc. All rights reserved.
5 * Author: Alex Williamson <alex.williamson@redhat.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * Register a device specific region through which to provide read-only
12 * access to the Intel IGD opregion. The register defining the opregion
13 * address is also virtualized to prevent user modification.
17 #include <linux/pci.h>
18 #include <linux/uaccess.h>
19 #include <linux/vfio.h>
21 #include "vfio_pci_private.h"
23 #define OPREGION_SIGNATURE "IntelGraphicsMem"
24 #define OPREGION_SIZE (8 * 1024)
25 #define OPREGION_PCI_ADDR 0xfc
27 static size_t vfio_pci_igd_rw(struct vfio_pci_device
*vdev
, char __user
*buf
,
28 size_t count
, loff_t
*ppos
, bool iswrite
)
30 unsigned int i
= VFIO_PCI_OFFSET_TO_INDEX(*ppos
) - VFIO_PCI_NUM_REGIONS
;
31 void *base
= vdev
->region
[i
].data
;
32 loff_t pos
= *ppos
& VFIO_PCI_OFFSET_MASK
;
34 if (pos
>= vdev
->region
[i
].size
|| iswrite
)
37 count
= min(count
, (size_t)(vdev
->region
[i
].size
- pos
));
39 if (copy_to_user(buf
, base
+ pos
, count
))
47 static void vfio_pci_igd_release(struct vfio_pci_device
*vdev
,
48 struct vfio_pci_region
*region
)
50 memunmap(region
->data
);
53 static const struct vfio_pci_regops vfio_pci_igd_regops
= {
54 .rw
= vfio_pci_igd_rw
,
55 .release
= vfio_pci_igd_release
,
58 static int vfio_pci_igd_opregion_init(struct vfio_pci_device
*vdev
)
60 __le32
*dwordp
= (__le32
*)(vdev
->vconfig
+ OPREGION_PCI_ADDR
);
65 ret
= pci_read_config_dword(vdev
->pdev
, OPREGION_PCI_ADDR
, &addr
);
69 if (!addr
|| !(~addr
))
72 base
= memremap(addr
, OPREGION_SIZE
, MEMREMAP_WB
);
76 if (memcmp(base
, OPREGION_SIGNATURE
, 16)) {
81 size
= le32_to_cpu(*(__le32
*)(base
+ 16));
87 size
*= 1024; /* In KB */
89 if (size
!= OPREGION_SIZE
) {
91 base
= memremap(addr
, size
, MEMREMAP_WB
);
96 ret
= vfio_pci_register_dev_region(vdev
,
97 PCI_VENDOR_ID_INTEL
| VFIO_REGION_TYPE_PCI_VENDOR_TYPE
,
98 VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION
,
99 &vfio_pci_igd_regops
, size
, VFIO_REGION_INFO_FLAG_READ
, base
);
105 /* Fill vconfig with the hw value and virtualize register */
106 *dwordp
= cpu_to_le32(addr
);
107 memset(vdev
->pci_config_map
+ OPREGION_PCI_ADDR
,
108 PCI_CAP_ID_INVALID_VIRT
, 4);
113 static size_t vfio_pci_igd_cfg_rw(struct vfio_pci_device
*vdev
,
114 char __user
*buf
, size_t count
, loff_t
*ppos
,
117 unsigned int i
= VFIO_PCI_OFFSET_TO_INDEX(*ppos
) - VFIO_PCI_NUM_REGIONS
;
118 struct pci_dev
*pdev
= vdev
->region
[i
].data
;
119 loff_t pos
= *ppos
& VFIO_PCI_OFFSET_MASK
;
123 if (pos
>= vdev
->region
[i
].size
|| iswrite
)
126 size
= count
= min(count
, (size_t)(vdev
->region
[i
].size
- pos
));
128 if ((pos
& 1) && size
) {
131 ret
= pci_user_read_config_byte(pdev
, pos
, &val
);
133 return pcibios_err_to_errno(ret
);
135 if (copy_to_user(buf
+ count
- size
, &val
, 1))
142 if ((pos
& 3) && size
> 2) {
145 ret
= pci_user_read_config_word(pdev
, pos
, &val
);
147 return pcibios_err_to_errno(ret
);
149 val
= cpu_to_le16(val
);
150 if (copy_to_user(buf
+ count
- size
, &val
, 2))
160 ret
= pci_user_read_config_dword(pdev
, pos
, &val
);
162 return pcibios_err_to_errno(ret
);
164 val
= cpu_to_le32(val
);
165 if (copy_to_user(buf
+ count
- size
, &val
, 4))
175 ret
= pci_user_read_config_word(pdev
, pos
, &val
);
177 return pcibios_err_to_errno(ret
);
179 val
= cpu_to_le16(val
);
180 if (copy_to_user(buf
+ count
- size
, &val
, 2))
190 ret
= pci_user_read_config_byte(pdev
, pos
, &val
);
192 return pcibios_err_to_errno(ret
);
194 if (copy_to_user(buf
+ count
- size
, &val
, 1))
206 static void vfio_pci_igd_cfg_release(struct vfio_pci_device
*vdev
,
207 struct vfio_pci_region
*region
)
209 struct pci_dev
*pdev
= region
->data
;
214 static const struct vfio_pci_regops vfio_pci_igd_cfg_regops
= {
215 .rw
= vfio_pci_igd_cfg_rw
,
216 .release
= vfio_pci_igd_cfg_release
,
219 static int vfio_pci_igd_cfg_init(struct vfio_pci_device
*vdev
)
221 struct pci_dev
*host_bridge
, *lpc_bridge
;
224 host_bridge
= pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
228 if (host_bridge
->vendor
!= PCI_VENDOR_ID_INTEL
||
229 host_bridge
->class != (PCI_CLASS_BRIDGE_HOST
<< 8)) {
230 pci_dev_put(host_bridge
);
234 ret
= vfio_pci_register_dev_region(vdev
,
235 PCI_VENDOR_ID_INTEL
| VFIO_REGION_TYPE_PCI_VENDOR_TYPE
,
236 VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG
,
237 &vfio_pci_igd_cfg_regops
, host_bridge
->cfg_size
,
238 VFIO_REGION_INFO_FLAG_READ
, host_bridge
);
240 pci_dev_put(host_bridge
);
244 lpc_bridge
= pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x1f, 0));
248 if (lpc_bridge
->vendor
!= PCI_VENDOR_ID_INTEL
||
249 lpc_bridge
->class != (PCI_CLASS_BRIDGE_ISA
<< 8)) {
250 pci_dev_put(lpc_bridge
);
254 ret
= vfio_pci_register_dev_region(vdev
,
255 PCI_VENDOR_ID_INTEL
| VFIO_REGION_TYPE_PCI_VENDOR_TYPE
,
256 VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG
,
257 &vfio_pci_igd_cfg_regops
, lpc_bridge
->cfg_size
,
258 VFIO_REGION_INFO_FLAG_READ
, lpc_bridge
);
260 pci_dev_put(lpc_bridge
);
267 int vfio_pci_igd_init(struct vfio_pci_device
*vdev
)
271 ret
= vfio_pci_igd_opregion_init(vdev
);
275 ret
= vfio_pci_igd_cfg_init(vdev
);