1b0d56e3cSJean-Philippe Brucker #include "kvm/virtio-pci.h"
2b0d56e3cSJean-Philippe Brucker
3b0d56e3cSJean-Philippe Brucker #include "kvm/ioport.h"
4b0d56e3cSJean-Philippe Brucker #include "kvm/virtio.h"
5b0d56e3cSJean-Philippe Brucker #include "kvm/virtio-pci-dev.h"
6b0d56e3cSJean-Philippe Brucker
7b0d56e3cSJean-Philippe Brucker #include <linux/virtio_config.h>
8b0d56e3cSJean-Philippe Brucker
9b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_COMMON_SIZE sizeof(struct virtio_pci_common_cfg)
10b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_COMMON_START 0
11b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_COMMON_END (VPCI_CFG_COMMON_SIZE - 1)
12b0d56e3cSJean-Philippe Brucker /*
13b0d56e3cSJean-Philippe Brucker * Use a naturally aligned 4-byte doorbell, in case we ever want to
14b0d56e3cSJean-Philippe Brucker * implement VIRTIO_F_NOTIFICATION_DATA
15b0d56e3cSJean-Philippe Brucker */
16b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_NOTIFY_SIZE 4
17b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_NOTIFY_START (VPCI_CFG_COMMON_END + 1)
18b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_NOTIFY_END (VPCI_CFG_COMMON_END + VPCI_CFG_NOTIFY_SIZE)
19b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_ISR_SIZE 4
20b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_ISR_START (VPCI_CFG_NOTIFY_END + 1)
21b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_ISR_END (VPCI_CFG_NOTIFY_END + VPCI_CFG_ISR_SIZE)
22b0d56e3cSJean-Philippe Brucker /*
23b0d56e3cSJean-Philippe Brucker * We're at 64 bytes. Use the remaining 192 bytes in PCI_IO_SIZE for the
24b0d56e3cSJean-Philippe Brucker * device-specific config space. It's sufficient for the devices we
25b0d56e3cSJean-Philippe Brucker * currently implement (virtio_blk_config is 60 bytes) and, I think, all
26b0d56e3cSJean-Philippe Brucker * existing virtio 1.2 devices.
27b0d56e3cSJean-Philippe Brucker */
28b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_DEV_START (VPCI_CFG_ISR_END + 1)
29b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_DEV_END ((PCI_IO_SIZE) - 1)
30b0d56e3cSJean-Philippe Brucker #define VPCI_CFG_DEV_SIZE (VPCI_CFG_DEV_END - VPCI_CFG_DEV_START + 1)
31b0d56e3cSJean-Philippe Brucker
32b0d56e3cSJean-Philippe Brucker #define vpci_selected_vq(vpci) \
33b0d56e3cSJean-Philippe Brucker vdev->ops->get_vq((vpci)->kvm, (vpci)->dev, (vpci)->queue_selector)
34b0d56e3cSJean-Philippe Brucker
35b0d56e3cSJean-Philippe Brucker typedef bool (*access_handler_t)(struct virtio_device *, unsigned long, void *, int);
36b0d56e3cSJean-Philippe Brucker
virtio_pci__common_write(struct virtio_device * vdev,unsigned long offset,void * data,int size)37b0d56e3cSJean-Philippe Brucker static bool virtio_pci__common_write(struct virtio_device *vdev,
38b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
39b0d56e3cSJean-Philippe Brucker {
40b0d56e3cSJean-Philippe Brucker u64 features;
41b0d56e3cSJean-Philippe Brucker u32 val, gsi, vec;
42b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
43b0d56e3cSJean-Philippe Brucker
44b0d56e3cSJean-Philippe Brucker switch (offset - VPCI_CFG_COMMON_START) {
45b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_DFSELECT:
46b0d56e3cSJean-Philippe Brucker vpci->device_features_sel = ioport__read32(data);
47b0d56e3cSJean-Philippe Brucker break;
48b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_GFSELECT:
49b0d56e3cSJean-Philippe Brucker vpci->driver_features_sel = ioport__read32(data);
50b0d56e3cSJean-Philippe Brucker break;
51b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_GF:
52b0d56e3cSJean-Philippe Brucker val = ioport__read32(data);
53b0d56e3cSJean-Philippe Brucker if (vpci->driver_features_sel > 1)
54b0d56e3cSJean-Philippe Brucker break;
55b0d56e3cSJean-Philippe Brucker
56b0d56e3cSJean-Philippe Brucker features = (u64)val << (32 * vpci->driver_features_sel);
57b0d56e3cSJean-Philippe Brucker virtio_set_guest_features(vpci->kvm, vdev, vpci->dev, features);
58b0d56e3cSJean-Philippe Brucker break;
59b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_MSIX:
60b0d56e3cSJean-Philippe Brucker vec = vpci->config_vector = ioport__read16(data);
61b0d56e3cSJean-Philippe Brucker gsi = virtio_pci__add_msix_route(vpci, vec);
62b0d56e3cSJean-Philippe Brucker if (gsi < 0)
63b0d56e3cSJean-Philippe Brucker break;
64b0d56e3cSJean-Philippe Brucker
65b0d56e3cSJean-Philippe Brucker vpci->config_gsi = gsi;
66b0d56e3cSJean-Philippe Brucker break;
67b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_STATUS:
68b0d56e3cSJean-Philippe Brucker vpci->status = ioport__read8(data);
69b0d56e3cSJean-Philippe Brucker virtio_notify_status(vpci->kvm, vdev, vpci->dev, vpci->status);
70b0d56e3cSJean-Philippe Brucker break;
71b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_SELECT:
72b0d56e3cSJean-Philippe Brucker val = ioport__read16(data);
73b0d56e3cSJean-Philippe Brucker if (val >= (u32)vdev->ops->get_vq_count(vpci->kvm, vpci->dev))
74b0d56e3cSJean-Philippe Brucker pr_warning("invalid vq number %u", val);
75b0d56e3cSJean-Philippe Brucker else
76b0d56e3cSJean-Philippe Brucker vpci->queue_selector = val;
77b0d56e3cSJean-Philippe Brucker break;
78b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_SIZE:
79b0d56e3cSJean-Philippe Brucker vdev->ops->set_size_vq(vpci->kvm, vpci->dev,
80b0d56e3cSJean-Philippe Brucker vpci->queue_selector,
81b0d56e3cSJean-Philippe Brucker ioport__read16(data));
82b0d56e3cSJean-Philippe Brucker break;
83b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_MSIX:
84b0d56e3cSJean-Philippe Brucker vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
85b0d56e3cSJean-Philippe Brucker
86b0d56e3cSJean-Philippe Brucker gsi = virtio_pci__add_msix_route(vpci, vec);
87b0d56e3cSJean-Philippe Brucker if (gsi < 0)
88b0d56e3cSJean-Philippe Brucker break;
89b0d56e3cSJean-Philippe Brucker
90b0d56e3cSJean-Philippe Brucker vpci->gsis[vpci->queue_selector] = gsi;
91b0d56e3cSJean-Philippe Brucker if (vdev->ops->notify_vq_gsi)
92b0d56e3cSJean-Philippe Brucker vdev->ops->notify_vq_gsi(vpci->kvm, vpci->dev,
93b0d56e3cSJean-Philippe Brucker vpci->queue_selector, gsi);
94b0d56e3cSJean-Philippe Brucker break;
95b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_ENABLE:
96b0d56e3cSJean-Philippe Brucker val = ioport__read16(data);
97b0d56e3cSJean-Philippe Brucker if (val)
98b0d56e3cSJean-Philippe Brucker virtio_pci_init_vq(vpci->kvm, vdev, vpci->queue_selector);
99b0d56e3cSJean-Philippe Brucker else
100b0d56e3cSJean-Philippe Brucker virtio_pci_exit_vq(vpci->kvm, vdev, vpci->queue_selector);
101b0d56e3cSJean-Philippe Brucker break;
102b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_DESCLO:
103b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.desc_lo = ioport__read32(data);
104b0d56e3cSJean-Philippe Brucker break;
105b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_DESCHI:
106b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.desc_hi = ioport__read32(data);
107b0d56e3cSJean-Philippe Brucker break;
108b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_AVAILLO:
109b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.avail_lo = ioport__read32(data);
110b0d56e3cSJean-Philippe Brucker break;
111b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_AVAILHI:
112b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.avail_hi = ioport__read32(data);
113b0d56e3cSJean-Philippe Brucker break;
114b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_USEDLO:
115b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.used_lo = ioport__read32(data);
116b0d56e3cSJean-Philippe Brucker break;
117b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_USEDHI:
118b0d56e3cSJean-Philippe Brucker vpci_selected_vq(vpci)->vring_addr.used_hi = ioport__read32(data);
119b0d56e3cSJean-Philippe Brucker break;
120b0d56e3cSJean-Philippe Brucker }
121b0d56e3cSJean-Philippe Brucker
122b0d56e3cSJean-Philippe Brucker return true;
123b0d56e3cSJean-Philippe Brucker }
124b0d56e3cSJean-Philippe Brucker
virtio_pci__notify_write(struct virtio_device * vdev,unsigned long offset,void * data,int size)125b0d56e3cSJean-Philippe Brucker static bool virtio_pci__notify_write(struct virtio_device *vdev,
126b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
127b0d56e3cSJean-Philippe Brucker {
128b0d56e3cSJean-Philippe Brucker u16 vq = ioport__read16(data);
129b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
130b0d56e3cSJean-Philippe Brucker
131b0d56e3cSJean-Philippe Brucker vdev->ops->notify_vq(vpci->kvm, vpci->dev, vq);
132b0d56e3cSJean-Philippe Brucker
133b0d56e3cSJean-Philippe Brucker return true;
134b0d56e3cSJean-Philippe Brucker }
135b0d56e3cSJean-Philippe Brucker
virtio_pci__config_write(struct virtio_device * vdev,unsigned long offset,void * data,int size)136b0d56e3cSJean-Philippe Brucker static bool virtio_pci__config_write(struct virtio_device *vdev,
137b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
138b0d56e3cSJean-Philippe Brucker {
139b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
140b0d56e3cSJean-Philippe Brucker
141b0d56e3cSJean-Philippe Brucker return virtio_access_config(vpci->kvm, vdev, vpci->dev,
142b0d56e3cSJean-Philippe Brucker offset - VPCI_CFG_DEV_START, data, size,
143b0d56e3cSJean-Philippe Brucker true);
144b0d56e3cSJean-Philippe Brucker }
145b0d56e3cSJean-Philippe Brucker
virtio_pci__common_read(struct virtio_device * vdev,unsigned long offset,void * data,int size)146b0d56e3cSJean-Philippe Brucker static bool virtio_pci__common_read(struct virtio_device *vdev,
147b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
148b0d56e3cSJean-Philippe Brucker {
149b0d56e3cSJean-Philippe Brucker u32 val;
150b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
151b0d56e3cSJean-Philippe Brucker u64 features = 1ULL << VIRTIO_F_VERSION_1;
152b0d56e3cSJean-Philippe Brucker
153b0d56e3cSJean-Philippe Brucker switch (offset - VPCI_CFG_COMMON_START) {
154b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_DFSELECT:
155b0d56e3cSJean-Philippe Brucker val = vpci->device_features_sel;
156b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
157b0d56e3cSJean-Philippe Brucker break;
158b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_DF:
159b0d56e3cSJean-Philippe Brucker if (vpci->device_features_sel > 1)
160b0d56e3cSJean-Philippe Brucker break;
161b0d56e3cSJean-Philippe Brucker features |= vdev->ops->get_host_features(vpci->kvm, vpci->dev);
162b0d56e3cSJean-Philippe Brucker val = features >> (32 * vpci->device_features_sel);
163b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
164b0d56e3cSJean-Philippe Brucker break;
165b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_GFSELECT:
166b0d56e3cSJean-Philippe Brucker val = vpci->driver_features_sel;
167b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
168b0d56e3cSJean-Philippe Brucker break;
169b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_MSIX:
170b0d56e3cSJean-Philippe Brucker val = vpci->config_vector;
171b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
172b0d56e3cSJean-Philippe Brucker break;
173b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_NUMQ:
174b0d56e3cSJean-Philippe Brucker val = vdev->ops->get_vq_count(vpci->kvm, vpci->dev);
175b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
176b0d56e3cSJean-Philippe Brucker break;
177b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_STATUS:
178b0d56e3cSJean-Philippe Brucker ioport__write8(data, vpci->status);
179b0d56e3cSJean-Philippe Brucker break;
180b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_CFGGENERATION:
181b0d56e3cSJean-Philippe Brucker /*
182b0d56e3cSJean-Philippe Brucker * The config generation changes when the device updates a
183b0d56e3cSJean-Philippe Brucker * config field larger than 32 bits, that the driver may read
184b0d56e3cSJean-Philippe Brucker * using multiple accesses. Since kvmtool doesn't use any
185b0d56e3cSJean-Philippe Brucker * mutable config field larger than 32 bits, the generation is
186b0d56e3cSJean-Philippe Brucker * constant.
187b0d56e3cSJean-Philippe Brucker */
188b0d56e3cSJean-Philippe Brucker ioport__write8(data, 0);
189b0d56e3cSJean-Philippe Brucker break;
190b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_SELECT:
191b0d56e3cSJean-Philippe Brucker ioport__write16(data, vpci->queue_selector);
192b0d56e3cSJean-Philippe Brucker break;
193b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_SIZE:
194b0d56e3cSJean-Philippe Brucker val = vdev->ops->get_size_vq(vpci->kvm, vpci->dev,
195b0d56e3cSJean-Philippe Brucker vpci->queue_selector);
196b0d56e3cSJean-Philippe Brucker ioport__write16(data, val);
197b0d56e3cSJean-Philippe Brucker break;
198b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_MSIX:
199b0d56e3cSJean-Philippe Brucker val = vpci->vq_vector[vpci->queue_selector];
200b0d56e3cSJean-Philippe Brucker ioport__write16(data, val);
201b0d56e3cSJean-Philippe Brucker break;
202b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_ENABLE:
203b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->enabled;
204b0d56e3cSJean-Philippe Brucker ioport__write16(data, val);
205b0d56e3cSJean-Philippe Brucker break;
206b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_NOFF:
207b0d56e3cSJean-Philippe Brucker val = vpci->queue_selector;
208b0d56e3cSJean-Philippe Brucker ioport__write16(data, val);
209b0d56e3cSJean-Philippe Brucker break;
210b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_DESCLO:
211b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.desc_lo;
212b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
213b0d56e3cSJean-Philippe Brucker break;
214b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_DESCHI:
215b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.desc_hi;
216b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
217b0d56e3cSJean-Philippe Brucker break;
218b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_AVAILLO:
219b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.avail_lo;
220b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
221b0d56e3cSJean-Philippe Brucker break;
222b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_AVAILHI:
223b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.avail_hi;
224b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
225b0d56e3cSJean-Philippe Brucker break;
226b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_USEDLO:
227b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.used_lo;
228b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
229b0d56e3cSJean-Philippe Brucker break;
230b0d56e3cSJean-Philippe Brucker case VIRTIO_PCI_COMMON_Q_USEDHI:
231b0d56e3cSJean-Philippe Brucker val = vpci_selected_vq(vpci)->vring_addr.used_hi;
232b0d56e3cSJean-Philippe Brucker ioport__write32(data, val);
233b0d56e3cSJean-Philippe Brucker break;
234b0d56e3cSJean-Philippe Brucker };
235b0d56e3cSJean-Philippe Brucker
236b0d56e3cSJean-Philippe Brucker return true;
237b0d56e3cSJean-Philippe Brucker }
238b0d56e3cSJean-Philippe Brucker
virtio_pci__isr_read(struct virtio_device * vdev,unsigned long offset,void * data,int size)239b0d56e3cSJean-Philippe Brucker static bool virtio_pci__isr_read(struct virtio_device *vdev,
240b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
241b0d56e3cSJean-Philippe Brucker {
242b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
243b0d56e3cSJean-Philippe Brucker
244b0d56e3cSJean-Philippe Brucker if (WARN_ON(offset - VPCI_CFG_ISR_START != 0))
245b0d56e3cSJean-Philippe Brucker return false;
246b0d56e3cSJean-Philippe Brucker
247b0d56e3cSJean-Philippe Brucker ioport__write8(data, vpci->isr);
248*fe218273SJean-Philippe Brucker kvm__irq_line(vpci->kvm, vpci->legacy_irq_line, VIRTIO_IRQ_LOW);
249b0d56e3cSJean-Philippe Brucker vpci->isr = 0;
250b0d56e3cSJean-Philippe Brucker
251b0d56e3cSJean-Philippe Brucker return 0;
252b0d56e3cSJean-Philippe Brucker }
253b0d56e3cSJean-Philippe Brucker
virtio_pci__config_read(struct virtio_device * vdev,unsigned long offset,void * data,int size)254b0d56e3cSJean-Philippe Brucker static bool virtio_pci__config_read(struct virtio_device *vdev,
255b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size)
256b0d56e3cSJean-Philippe Brucker {
257b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
258b0d56e3cSJean-Philippe Brucker
259b0d56e3cSJean-Philippe Brucker return virtio_access_config(vpci->kvm, vdev, vpci->dev,
260b0d56e3cSJean-Philippe Brucker offset - VPCI_CFG_DEV_START, data, size,
261b0d56e3cSJean-Philippe Brucker false);
262b0d56e3cSJean-Philippe Brucker }
263b0d56e3cSJean-Philippe Brucker
virtio_pci_access(struct kvm_cpu * vcpu,struct virtio_device * vdev,unsigned long offset,void * data,int size,bool write)264b0d56e3cSJean-Philippe Brucker static bool virtio_pci_access(struct kvm_cpu *vcpu, struct virtio_device *vdev,
265b0d56e3cSJean-Philippe Brucker unsigned long offset, void *data, int size,
266b0d56e3cSJean-Philippe Brucker bool write)
267b0d56e3cSJean-Philippe Brucker {
268b0d56e3cSJean-Philippe Brucker access_handler_t handler = NULL;
269b0d56e3cSJean-Philippe Brucker
270b0d56e3cSJean-Philippe Brucker switch (offset) {
271b0d56e3cSJean-Philippe Brucker case VPCI_CFG_COMMON_START...VPCI_CFG_COMMON_END:
272b0d56e3cSJean-Philippe Brucker if (write)
273b0d56e3cSJean-Philippe Brucker handler = virtio_pci__common_write;
274b0d56e3cSJean-Philippe Brucker else
275b0d56e3cSJean-Philippe Brucker handler = virtio_pci__common_read;
276b0d56e3cSJean-Philippe Brucker break;
277b0d56e3cSJean-Philippe Brucker case VPCI_CFG_NOTIFY_START...VPCI_CFG_NOTIFY_END:
278b0d56e3cSJean-Philippe Brucker if (write)
279b0d56e3cSJean-Philippe Brucker handler = virtio_pci__notify_write;
280b0d56e3cSJean-Philippe Brucker break;
281b0d56e3cSJean-Philippe Brucker case VPCI_CFG_ISR_START...VPCI_CFG_ISR_END:
282b0d56e3cSJean-Philippe Brucker if (!write)
283b0d56e3cSJean-Philippe Brucker handler = virtio_pci__isr_read;
284b0d56e3cSJean-Philippe Brucker break;
285b0d56e3cSJean-Philippe Brucker case VPCI_CFG_DEV_START...VPCI_CFG_DEV_END:
286b0d56e3cSJean-Philippe Brucker if (write)
287b0d56e3cSJean-Philippe Brucker handler = virtio_pci__config_write;
288b0d56e3cSJean-Philippe Brucker else
289b0d56e3cSJean-Philippe Brucker handler = virtio_pci__config_read;
290b0d56e3cSJean-Philippe Brucker break;
291b0d56e3cSJean-Philippe Brucker }
292b0d56e3cSJean-Philippe Brucker
293b0d56e3cSJean-Philippe Brucker if (!handler)
294b0d56e3cSJean-Philippe Brucker return false;
295b0d56e3cSJean-Philippe Brucker
296b0d56e3cSJean-Philippe Brucker return handler(vdev, offset, data, size);
297b0d56e3cSJean-Philippe Brucker }
298b0d56e3cSJean-Philippe Brucker
virtio_pci_modern__io_mmio_callback(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)299b0d56e3cSJean-Philippe Brucker void virtio_pci_modern__io_mmio_callback(struct kvm_cpu *vcpu, u64 addr,
300b0d56e3cSJean-Philippe Brucker u8 *data, u32 len, u8 is_write,
301b0d56e3cSJean-Philippe Brucker void *ptr)
302b0d56e3cSJean-Philippe Brucker {
303b0d56e3cSJean-Philippe Brucker struct virtio_device *vdev = ptr;
304b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
305b0d56e3cSJean-Philippe Brucker u32 mmio_addr = virtio_pci__mmio_addr(vpci);
306b0d56e3cSJean-Philippe Brucker
307b0d56e3cSJean-Philippe Brucker virtio_pci_access(vcpu, vdev, addr - mmio_addr, data, len, is_write);
308b0d56e3cSJean-Philippe Brucker }
309b0d56e3cSJean-Philippe Brucker
virtio_pci_modern_init(struct virtio_device * vdev)310b0d56e3cSJean-Philippe Brucker int virtio_pci_modern_init(struct virtio_device *vdev)
311b0d56e3cSJean-Philippe Brucker {
312b0d56e3cSJean-Philippe Brucker int subsys_id;
313b0d56e3cSJean-Philippe Brucker struct virtio_pci *vpci = vdev->virtio;
314b0d56e3cSJean-Philippe Brucker struct pci_device_header *hdr = &vpci->pci_hdr;
315b0d56e3cSJean-Philippe Brucker
316b0d56e3cSJean-Philippe Brucker subsys_id = le16_to_cpu(hdr->subsys_id);
317b0d56e3cSJean-Philippe Brucker
318b0d56e3cSJean-Philippe Brucker hdr->device_id = cpu_to_le16(PCI_DEVICE_ID_VIRTIO_BASE + subsys_id);
319b0d56e3cSJean-Philippe Brucker hdr->subsys_id = cpu_to_le16(PCI_SUBSYS_ID_VIRTIO_BASE + subsys_id);
320b0d56e3cSJean-Philippe Brucker
321b0d56e3cSJean-Philippe Brucker vpci->doorbell_offset = VPCI_CFG_NOTIFY_START;
322b0d56e3cSJean-Philippe Brucker vdev->endian = VIRTIO_ENDIAN_LE;
323b0d56e3cSJean-Philippe Brucker
324b0d56e3cSJean-Philippe Brucker hdr->msix.next = PCI_CAP_OFF(hdr, virtio);
325b0d56e3cSJean-Philippe Brucker
326b0d56e3cSJean-Philippe Brucker hdr->virtio.common = (struct virtio_pci_cap) {
327b0d56e3cSJean-Philippe Brucker .cap_vndr = PCI_CAP_ID_VNDR,
328b0d56e3cSJean-Philippe Brucker .cap_next = PCI_CAP_OFF(hdr, virtio.notify),
329b0d56e3cSJean-Philippe Brucker .cap_len = sizeof(hdr->virtio.common),
330b0d56e3cSJean-Philippe Brucker .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
331b0d56e3cSJean-Philippe Brucker .bar = 1,
332b0d56e3cSJean-Philippe Brucker .offset = cpu_to_le32(VPCI_CFG_COMMON_START),
333b0d56e3cSJean-Philippe Brucker .length = cpu_to_le32(VPCI_CFG_COMMON_SIZE),
334b0d56e3cSJean-Philippe Brucker };
335b0d56e3cSJean-Philippe Brucker BUILD_BUG_ON(VPCI_CFG_COMMON_START & 0x3);
336b0d56e3cSJean-Philippe Brucker
337b0d56e3cSJean-Philippe Brucker hdr->virtio.notify = (struct virtio_pci_notify_cap) {
338b0d56e3cSJean-Philippe Brucker .cap.cap_vndr = PCI_CAP_ID_VNDR,
339b0d56e3cSJean-Philippe Brucker .cap.cap_next = PCI_CAP_OFF(hdr, virtio.isr),
340b0d56e3cSJean-Philippe Brucker .cap.cap_len = sizeof(hdr->virtio.notify),
341b0d56e3cSJean-Philippe Brucker .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
342b0d56e3cSJean-Philippe Brucker .cap.bar = 1,
343b0d56e3cSJean-Philippe Brucker .cap.offset = cpu_to_le32(VPCI_CFG_NOTIFY_START),
344b0d56e3cSJean-Philippe Brucker .cap.length = cpu_to_le32(VPCI_CFG_NOTIFY_SIZE),
345b0d56e3cSJean-Philippe Brucker /*
346b0d56e3cSJean-Philippe Brucker * Notify multiplier is 0, meaning that notifications are all on
347b0d56e3cSJean-Philippe Brucker * the same register
348b0d56e3cSJean-Philippe Brucker */
349b0d56e3cSJean-Philippe Brucker };
350b0d56e3cSJean-Philippe Brucker BUILD_BUG_ON(VPCI_CFG_NOTIFY_START & 0x3);
351b0d56e3cSJean-Philippe Brucker
352b0d56e3cSJean-Philippe Brucker hdr->virtio.isr = (struct virtio_pci_cap) {
353b0d56e3cSJean-Philippe Brucker .cap_vndr = PCI_CAP_ID_VNDR,
354b0d56e3cSJean-Philippe Brucker .cap_next = PCI_CAP_OFF(hdr, virtio.device),
355b0d56e3cSJean-Philippe Brucker .cap_len = sizeof(hdr->virtio.isr),
356b0d56e3cSJean-Philippe Brucker .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
357b0d56e3cSJean-Philippe Brucker .bar = 1,
358b0d56e3cSJean-Philippe Brucker .offset = cpu_to_le32(VPCI_CFG_ISR_START),
359b0d56e3cSJean-Philippe Brucker .length = cpu_to_le32(VPCI_CFG_ISR_SIZE),
360b0d56e3cSJean-Philippe Brucker };
361b0d56e3cSJean-Philippe Brucker
362b0d56e3cSJean-Philippe Brucker hdr->virtio.device = (struct virtio_pci_cap) {
363b0d56e3cSJean-Philippe Brucker .cap_vndr = PCI_CAP_ID_VNDR,
364b0d56e3cSJean-Philippe Brucker .cap_next = PCI_CAP_OFF(hdr, virtio.pci),
365b0d56e3cSJean-Philippe Brucker .cap_len = sizeof(hdr->virtio.device),
366b0d56e3cSJean-Philippe Brucker .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
367b0d56e3cSJean-Philippe Brucker .bar = 1,
368b0d56e3cSJean-Philippe Brucker .offset = cpu_to_le32(VPCI_CFG_DEV_START),
369b0d56e3cSJean-Philippe Brucker .length = cpu_to_le32(VPCI_CFG_DEV_SIZE),
370b0d56e3cSJean-Philippe Brucker };
371b0d56e3cSJean-Philippe Brucker BUILD_BUG_ON(VPCI_CFG_DEV_START & 0x3);
372b0d56e3cSJean-Philippe Brucker
373b0d56e3cSJean-Philippe Brucker /*
374b0d56e3cSJean-Philippe Brucker * TODO: implement this weird proxy capability (it is a "MUST" in the
375b0d56e3cSJean-Philippe Brucker * spec, but I don't know if anyone actually uses it).
376b0d56e3cSJean-Philippe Brucker * It doesn't use any BAR space. Instead the driver writes .cap.offset
377b0d56e3cSJean-Philippe Brucker * and .cap.length to access a register in a BAR.
378b0d56e3cSJean-Philippe Brucker */
379b0d56e3cSJean-Philippe Brucker hdr->virtio.pci = (struct virtio_pci_cfg_cap) {
380b0d56e3cSJean-Philippe Brucker .cap.cap_vndr = PCI_CAP_ID_VNDR,
381b0d56e3cSJean-Philippe Brucker .cap.cap_next = 0,
382b0d56e3cSJean-Philippe Brucker .cap.cap_len = sizeof(hdr->virtio.pci),
383b0d56e3cSJean-Philippe Brucker .cap.cfg_type = VIRTIO_PCI_CAP_PCI_CFG,
384b0d56e3cSJean-Philippe Brucker };
385b0d56e3cSJean-Philippe Brucker
386b0d56e3cSJean-Philippe Brucker return 0;
387b0d56e3cSJean-Philippe Brucker }
388