xref: /kvmtool/virtio/pci.c (revision 1599d7242db63a7742d5a526cd9476357d7e1e92)
1 #include "kvm/virtio-pci.h"
2 
3 #include "kvm/ioport.h"
4 #include "kvm/kvm.h"
5 #include "kvm/virtio-pci-dev.h"
6 #include "kvm/irq.h"
7 #include "kvm/virtio.h"
8 #include "kvm/ioeventfd.h"
9 
10 #include <linux/virtio_pci.h>
11 #include <string.h>
12 
13 static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
14 {
15 	struct virtio_pci_ioevent_param *ioeventfd = param;
16 
17 	ioeventfd->vpci->ops.notify_vq(kvm, ioeventfd->vpci->dev, ioeventfd->vq);
18 }
19 
20 static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_pci *vpci, u32 vq)
21 {
22 	struct ioevent ioevent;
23 
24 	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
25 		.vpci		= vpci,
26 		.vq		= vq,
27 	};
28 
29 	ioevent = (struct ioevent) {
30 		.io_addr	= vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
31 		.io_len		= sizeof(u16),
32 		.fn		= virtio_pci__ioevent_callback,
33 		.fn_ptr		= &vpci->ioeventfds[vq],
34 		.datamatch	= vq,
35 		.fn_kvm		= kvm,
36 		.fd		= eventfd(0, 0),
37 	};
38 
39 	ioeventfd__add_event(&ioevent);
40 
41 	return 0;
42 }
43 
44 static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_pci *vpci, u16 port,
45 					void *data, int size, int offset)
46 {
47 	u32 config_offset;
48 	int type = virtio__get_dev_specific_field(offset - 20, vpci->msix_enabled,
49 							0, &config_offset);
50 	if (type == VIRTIO_PCI_O_MSIX) {
51 		switch (offset) {
52 		case VIRTIO_MSI_CONFIG_VECTOR:
53 			ioport__write16(data, vpci->config_vector);
54 			break;
55 		case VIRTIO_MSI_QUEUE_VECTOR:
56 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
57 			break;
58 		};
59 
60 		return true;
61 	} else if (type == VIRTIO_PCI_O_CONFIG) {
62 		u8 cfg;
63 
64 		cfg = vpci->ops.get_config(kvm, vpci->dev, config_offset);
65 		ioport__write8(data, cfg);
66 		return true;
67 	}
68 
69 	return false;
70 }
71 
72 static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
73 {
74 	unsigned long offset;
75 	bool ret = true;
76 	struct virtio_pci *vpci;
77 	u32 val;
78 
79 	vpci = ioport->priv;
80 	offset = port - vpci->base_addr;
81 
82 	switch (offset) {
83 	case VIRTIO_PCI_HOST_FEATURES:
84 		val = vpci->ops.get_host_features(kvm, vpci->dev);
85 		ioport__write32(data, val);
86 		break;
87 	case VIRTIO_PCI_QUEUE_PFN:
88 		val = vpci->ops.get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
89 		ioport__write32(data, val);
90 		break;
91 	case VIRTIO_PCI_QUEUE_NUM:
92 		val = vpci->ops.get_size_vq(kvm, vpci->dev, vpci->queue_selector);
93 		ioport__write32(data, val);
94 		break;
95 		break;
96 	case VIRTIO_PCI_STATUS:
97 		ioport__write8(data, vpci->status);
98 		break;
99 	case VIRTIO_PCI_ISR:
100 		ioport__write8(data, vpci->isr);
101 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
102 		vpci->isr = VIRTIO_IRQ_LOW;
103 		break;
104 	default:
105 		ret = virtio_pci__specific_io_in(kvm, vpci, port, data, size, offset);
106 		break;
107 	};
108 
109 	return ret;
110 }
111 
112 static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_pci *vpci, u16 port,
113 					void *data, int size, int offset)
114 {
115 	u32 config_offset, gsi, vec;
116 	int type = virtio__get_dev_specific_field(offset - 20, vpci->msix_enabled,
117 							0, &config_offset);
118 	if (type == VIRTIO_PCI_O_MSIX) {
119 		switch (offset) {
120 		case VIRTIO_MSI_CONFIG_VECTOR:
121 			vec = vpci->config_vector = ioport__read16(data);
122 
123 			gsi = irq__add_msix_route(kvm,
124 						  vpci->pci_hdr.msix.table[vec].low,
125 						  vpci->pci_hdr.msix.table[vec].high,
126 						  vpci->pci_hdr.msix.table[vec].data);
127 
128 			vpci->config_gsi = gsi;
129 			break;
130 		case VIRTIO_MSI_QUEUE_VECTOR: {
131 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
132 
133 			gsi = irq__add_msix_route(kvm,
134 						  vpci->pci_hdr.msix.table[vec].low,
135 						  vpci->pci_hdr.msix.table[vec].high,
136 						  vpci->pci_hdr.msix.table[vec].data);
137 			vpci->gsis[vpci->queue_selector] = gsi;
138 			break;
139 		}
140 		};
141 
142 		return true;
143 	} else if (type == VIRTIO_PCI_O_CONFIG) {
144 		vpci->ops.set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
145 
146 		return true;
147 	}
148 
149 	return false;
150 }
151 
152 static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
153 {
154 	unsigned long offset;
155 	bool ret = true;
156 	struct virtio_pci *vpci;
157 	u32 val;
158 
159 	vpci = ioport->priv;
160 	offset = port - vpci->base_addr;
161 
162 	switch (offset) {
163 	case VIRTIO_PCI_GUEST_FEATURES:
164 		val = ioport__read32(data);
165 		vpci->ops.set_guest_features(kvm, vpci, val);
166 		break;
167 	case VIRTIO_PCI_QUEUE_PFN:
168 		val = ioport__read32(data);
169 		virtio_pci__init_ioeventfd(kvm, vpci, vpci->queue_selector);
170 		vpci->ops.init_vq(kvm, vpci->dev, vpci->queue_selector, val);
171 		break;
172 	case VIRTIO_PCI_QUEUE_SEL:
173 		vpci->queue_selector	= ioport__read16(data);
174 		break;
175 	case VIRTIO_PCI_QUEUE_NOTIFY:
176 		val			= ioport__read16(data);
177 		vpci->ops.notify_vq(kvm, vpci->dev, val);
178 		break;
179 	case VIRTIO_PCI_STATUS:
180 		vpci->status		= ioport__read8(data);
181 		break;
182 	default:
183 		ret = virtio_pci__specific_io_out(kvm, vpci, port, data, size, offset);
184 		break;
185 	};
186 
187 	return ret;
188 }
189 
190 static struct ioport_operations virtio_pci__io_ops = {
191 	.io_in	= virtio_pci__io_in,
192 	.io_out	= virtio_pci__io_out,
193 };
194 
195 static void callback_mmio(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
196 {
197 	struct virtio_pci *vpci = ptr;
198 	void *table = &vpci->pci_hdr.msix.table;
199 
200 	vpci->msix_enabled = 1;
201 	if (is_write)
202 		memcpy(table + addr - vpci->msix_io_block, data, len);
203 	else
204 		memcpy(data, table + addr - vpci->msix_io_block, len);
205 }
206 
207 int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_pci *vpci, u32 vq)
208 {
209 	kvm__irq_line(kvm, vpci->gsis[vq], VIRTIO_IRQ_HIGH);
210 
211 	return 0;
212 }
213 
214 int virtio_pci__signal_config(struct kvm *kvm, struct virtio_pci *vpci)
215 {
216 	kvm__irq_line(kvm, vpci->config_gsi, VIRTIO_IRQ_HIGH);
217 
218 	return 0;
219 }
220 
221 int virtio_pci__init(struct kvm *kvm, struct virtio_pci *vpci, void *dev,
222 			int device_id, int subsys_id)
223 {
224 	u8 pin, line, ndev;
225 
226 	vpci->dev = dev;
227 	vpci->msix_io_block = pci_get_io_space_block();
228 
229 	vpci->base_addr = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vpci);
230 	kvm__register_mmio(kvm, vpci->msix_io_block, 0x100, callback_mmio, vpci);
231 
232 	vpci->pci_hdr = (struct pci_device_header) {
233 		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
234 		.device_id		= device_id,
235 		.header_type		= PCI_HEADER_TYPE_NORMAL,
236 		.revision_id		= 0,
237 		.class			= 0x010000,
238 		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
239 		.subsys_id		= subsys_id,
240 		.bar[0]			= vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO,
241 		.bar[1]			= vpci->msix_io_block |
242 					PCI_BASE_ADDRESS_SPACE_MEMORY |
243 					PCI_BASE_ADDRESS_MEM_TYPE_64,
244 		/* bar[2] is the continuation of bar[1] for 64bit addressing */
245 		.bar[2]			= 0,
246 		.status			= PCI_STATUS_CAP_LIST,
247 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
248 	};
249 
250 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
251 	vpci->pci_hdr.msix.next = 0;
252 	vpci->pci_hdr.msix.table_size = (VIRTIO_PCI_MAX_VQ + 1) | PCI_MSIX_FLAGS_ENABLE;
253 	vpci->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */
254 	vpci->config_vector = 0;
255 
256 	if (irq__register_device(VIRTIO_ID_RNG, &ndev, &pin, &line) < 0)
257 		return -1;
258 
259 	vpci->pci_hdr.irq_pin	= pin;
260 	vpci->pci_hdr.irq_line	= line;
261 	pci__register(&vpci->pci_hdr, ndev);
262 
263 	return 0;
264 }
265