aboutsummaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2018-05-11 11:05:03 -0400
committerAlex Williamson <alex.williamson@redhat.com>2018-06-08 12:24:09 -0400
commitd61fc96f47fdac1f031ed4eafa9106fe10cdaa37 (patch)
tree08b7ef5d11978851ada2d64d7e68d87a85de59a6 /samples
parent48d8476b41eed63567dd2f0ad125c895b9ac648a (diff)
sample: vfio mdev display - host device
Simple framebuffer display, demo-ing the vfio region display interface (VFIO_GFX_PLANE_TYPE_REGION). Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'samples')
-rw-r--r--samples/Kconfig8
-rw-r--r--samples/vfio-mdev/Makefile1
-rw-r--r--samples/vfio-mdev/mdpy-defs.h22
-rw-r--r--samples/vfio-mdev/mdpy.c807
4 files changed, 838 insertions, 0 deletions
diff --git a/samples/Kconfig b/samples/Kconfig
index 3db002b9e1d3..960f19b24df0 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -115,6 +115,14 @@ config SAMPLE_VFIO_MDEV_MTTY
115 Build a virtual tty sample driver for use as a VFIO 115 Build a virtual tty sample driver for use as a VFIO
116 mediated device 116 mediated device
117 117
118config SAMPLE_VFIO_MDEV_MDPY
119 tristate "Build VFIO mdpy example mediated device sample code -- loadable modules only"
120 depends on VFIO_MDEV_DEVICE && m
121 help
122 Build a virtual display sample driver for use as a VFIO
123 mediated device. It is a simple framebuffer and supports
124 the region display interface (VFIO_GFX_PLANE_TYPE_REGION).
125
118config SAMPLE_STATX 126config SAMPLE_STATX
119 bool "Build example extended-stat using code" 127 bool "Build example extended-stat using code"
120 depends on BROKEN 128 depends on BROKEN
diff --git a/samples/vfio-mdev/Makefile b/samples/vfio-mdev/Makefile
index cbbd868a50a8..031d6b88e9e9 100644
--- a/samples/vfio-mdev/Makefile
+++ b/samples/vfio-mdev/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_SAMPLE_VFIO_MDEV_MTTY) += mtty.o 1obj-$(CONFIG_SAMPLE_VFIO_MDEV_MTTY) += mtty.o
2obj-$(CONFIG_SAMPLE_VFIO_MDEV_MDPY) += mdpy.o
diff --git a/samples/vfio-mdev/mdpy-defs.h b/samples/vfio-mdev/mdpy-defs.h
new file mode 100644
index 000000000000..96b3b1b49d34
--- /dev/null
+++ b/samples/vfio-mdev/mdpy-defs.h
@@ -0,0 +1,22 @@
1/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2/*
3 * Simple pci display device.
4 *
5 * Framebuffer memory is pci bar 0.
6 * Configuration (read-only) is in pci config space.
7 * Format field uses drm fourcc codes.
8 * ATM only DRM_FORMAT_XRGB8888 is supported.
9 */
10
11/* pci ids */
12#define MDPY_PCI_VENDOR_ID 0x1b36 /* redhat */
13#define MDPY_PCI_DEVICE_ID 0x000f
14#define MDPY_PCI_SUBVENDOR_ID PCI_SUBVENDOR_ID_REDHAT_QUMRANET
15#define MDPY_PCI_SUBDEVICE_ID PCI_SUBDEVICE_ID_QEMU
16
17/* pci cfg space offsets for fb config (dword) */
18#define MDPY_VENDORCAP_OFFSET 0x40
19#define MDPY_VENDORCAP_SIZE 0x10
20#define MDPY_FORMAT_OFFSET (MDPY_VENDORCAP_OFFSET + 0x04)
21#define MDPY_WIDTH_OFFSET (MDPY_VENDORCAP_OFFSET + 0x08)
22#define MDPY_HEIGHT_OFFSET (MDPY_VENDORCAP_OFFSET + 0x0c)
diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c
new file mode 100644
index 000000000000..96e7969c473a
--- /dev/null
+++ b/samples/vfio-mdev/mdpy.c
@@ -0,0 +1,807 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Mediated virtual PCI display host device driver
4 *
5 * See mdpy-defs.h for device specs
6 *
7 * (c) Gerd Hoffmann <kraxel@redhat.com>
8 *
9 * based on mtty driver which is:
10 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
11 * Author: Neo Jia <cjia@nvidia.com>
12 * Kirti Wankhede <kwankhede@nvidia.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/kernel.h>
22#include <linux/slab.h>
23#include <linux/vmalloc.h>
24#include <linux/cdev.h>
25#include <linux/vfio.h>
26#include <linux/iommu.h>
27#include <linux/sysfs.h>
28#include <linux/mdev.h>
29#include <linux/pci.h>
30#include <drm/drm_fourcc.h>
31#include "mdpy-defs.h"
32
33#define MDPY_NAME "mdpy"
34#define MDPY_CLASS_NAME "mdpy"
35
36#define MDPY_CONFIG_SPACE_SIZE 0xff
37#define MDPY_MEMORY_BAR_OFFSET PAGE_SIZE
38#define MDPY_DISPLAY_REGION 16
39
40#define STORE_LE16(addr, val) (*(u16 *)addr = val)
41#define STORE_LE32(addr, val) (*(u32 *)addr = val)
42
43
44MODULE_LICENSE("GPL v2");
45
46static int max_devices = 4;
47module_param_named(count, max_devices, int, 0444);
48MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices");
49
50
51#define MDPY_TYPE_1 "vga"
52#define MDPY_TYPE_2 "xga"
53#define MDPY_TYPE_3 "hd"
54
55static const struct mdpy_type {
56 const char *name;
57 u32 format;
58 u32 bytepp;
59 u32 width;
60 u32 height;
61} mdpy_types[] = {
62 {
63 .name = MDPY_CLASS_NAME "-" MDPY_TYPE_1,
64 .format = DRM_FORMAT_XRGB8888,
65 .bytepp = 4,
66 .width = 640,
67 .height = 480,
68 }, {
69 .name = MDPY_CLASS_NAME "-" MDPY_TYPE_2,
70 .format = DRM_FORMAT_XRGB8888,
71 .bytepp = 4,
72 .width = 1024,
73 .height = 768,
74 }, {
75 .name = MDPY_CLASS_NAME "-" MDPY_TYPE_3,
76 .format = DRM_FORMAT_XRGB8888,
77 .bytepp = 4,
78 .width = 1920,
79 .height = 1080,
80 },
81};
82
83static dev_t mdpy_devt;
84static struct class *mdpy_class;
85static struct cdev mdpy_cdev;
86static struct device mdpy_dev;
87static u32 mdpy_count;
88
89/* State of each mdev device */
90struct mdev_state {
91 u8 *vconfig;
92 u32 bar_mask;
93 struct mutex ops_lock;
94 struct mdev_device *mdev;
95 struct vfio_device_info dev_info;
96
97 const struct mdpy_type *type;
98 u32 memsize;
99 void *memblk;
100};
101
102static const struct mdpy_type *mdpy_find_type(struct kobject *kobj)
103{
104 int i;
105
106 for (i = 0; i < ARRAY_SIZE(mdpy_types); i++)
107 if (strcmp(mdpy_types[i].name, kobj->name) == 0)
108 return mdpy_types + i;
109 return NULL;
110}
111
112static void mdpy_create_config_space(struct mdev_state *mdev_state)
113{
114 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_VENDOR_ID],
115 MDPY_PCI_VENDOR_ID);
116 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_DEVICE_ID],
117 MDPY_PCI_DEVICE_ID);
118 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_SUBSYSTEM_VENDOR_ID],
119 MDPY_PCI_SUBVENDOR_ID);
120 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_SUBSYSTEM_ID],
121 MDPY_PCI_SUBDEVICE_ID);
122
123 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_COMMAND],
124 PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
125 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_STATUS],
126 PCI_STATUS_CAP_LIST);
127 STORE_LE16((u16 *) &mdev_state->vconfig[PCI_CLASS_DEVICE],
128 PCI_CLASS_DISPLAY_OTHER);
129 mdev_state->vconfig[PCI_CLASS_REVISION] = 0x01;
130
131 STORE_LE32((u32 *) &mdev_state->vconfig[PCI_BASE_ADDRESS_0],
132 PCI_BASE_ADDRESS_SPACE_MEMORY |
133 PCI_BASE_ADDRESS_MEM_TYPE_32 |
134 PCI_BASE_ADDRESS_MEM_PREFETCH);
135 mdev_state->bar_mask = ~(mdev_state->memsize) + 1;
136
137 /* vendor specific capability for the config registers */
138 mdev_state->vconfig[PCI_CAPABILITY_LIST] = MDPY_VENDORCAP_OFFSET;
139 mdev_state->vconfig[MDPY_VENDORCAP_OFFSET + 0] = 0x09; /* vendor cap */
140 mdev_state->vconfig[MDPY_VENDORCAP_OFFSET + 1] = 0x00; /* next ptr */
141 mdev_state->vconfig[MDPY_VENDORCAP_OFFSET + 2] = MDPY_VENDORCAP_SIZE;
142 STORE_LE32((u32 *) &mdev_state->vconfig[MDPY_FORMAT_OFFSET],
143 mdev_state->type->format);
144 STORE_LE32((u32 *) &mdev_state->vconfig[MDPY_WIDTH_OFFSET],
145 mdev_state->type->width);
146 STORE_LE32((u32 *) &mdev_state->vconfig[MDPY_HEIGHT_OFFSET],
147 mdev_state->type->height);
148}
149
150static void handle_pci_cfg_write(struct mdev_state *mdev_state, u16 offset,
151 char *buf, u32 count)
152{
153 struct device *dev = mdev_dev(mdev_state->mdev);
154 u32 cfg_addr;
155
156 switch (offset) {
157 case PCI_BASE_ADDRESS_0:
158 cfg_addr = *(u32 *)buf;