Line 4
Link Here
|
4 |
* Copyright (c) 2017, Bryan Venteicher <bryanv@FreeBSD.org> |
4 |
* Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org> |
5 |
-- |
|
|
Line 29
Link Here
|
|
|
29 |
/* Driver for the VirtIO PCI interface. */ |
30 |
|
Line 30
Link Here
|
30 |
__FBSDID("$FreeBSD$"); |
32 |
__FBSDID("$FreeBSD: releng/12.1/sys/dev/virtio/pci/virtio_pci.c 328218 2018-01-21 15:42:36Z pfg $"); |
31 |
-- |
|
|
Lines 36-37
Link Here
|
36 |
#include <sys/sbuf.h> |
|
|
37 |
#include <sys/sysctl.h> |
Line 52
Link Here
|
52 |
#include <dev/virtio/pci/virtio_pci_var.h> |
|
|
Line 54
Link Here
|
54 |
#include "virtio_pci_if.h" |
53 |
#include "virtio_bus_if.h" |
55 |
-- |
|
|
Line 57
Link Here
|
57 |
static void vtpci_describe_features(struct vtpci_common *, const char *, |
56 |
struct vtpci_interrupt { |
58 |
-- |
57 |
struct resource *vti_irq; |
|
|
58 |
int vti_rid; |
59 |
void *vti_handler; |
60 |
}; |
61 |
|
62 |
struct vtpci_virtqueue { |
63 |
struct virtqueue *vtv_vq; |
64 |
int vtv_no_intr; |
65 |
}; |
66 |
|
67 |
struct vtpci_softc { |
68 |
device_t vtpci_dev; |
69 |
struct resource *vtpci_res; |
70 |
struct resource *vtpci_msix_res; |
71 |
uint64_t vtpci_features; |
72 |
uint32_t vtpci_flags; |
73 |
#define VTPCI_FLAG_NO_MSI 0x0001 |
74 |
#define VTPCI_FLAG_NO_MSIX 0x0002 |
75 |
#define VTPCI_FLAG_LEGACY 0x1000 |
76 |
#define VTPCI_FLAG_MSI 0x2000 |
77 |
#define VTPCI_FLAG_MSIX 0x4000 |
78 |
#define VTPCI_FLAG_SHARED_MSIX 0x8000 |
79 |
#define VTPCI_FLAG_ITYPE_MASK 0xF000 |
80 |
|
81 |
/* This "bus" will only ever have one child. */ |
82 |
device_t vtpci_child_dev; |
83 |
struct virtio_feature_desc *vtpci_child_feat_desc; |
84 |
|
85 |
int vtpci_nvqs; |
86 |
struct vtpci_virtqueue *vtpci_vqs; |
87 |
|
88 |
/* |
89 |
* Ideally, each virtqueue that the driver provides a callback for will |
90 |
* receive its own MSIX vector. If there are not sufficient vectors |
91 |
* available, then attempt to have all the VQs share one vector. For |
92 |
* MSIX, the configuration changed notifications must be on their own |
93 |
* vector. |
94 |
* |
95 |
* If MSIX is not available, we will attempt to have the whole device |
96 |
* share one MSI vector, and then, finally, one legacy interrupt. |
97 |
*/ |
98 |
struct vtpci_interrupt vtpci_device_interrupt; |
99 |
struct vtpci_interrupt *vtpci_msix_vq_interrupts; |
100 |
int vtpci_nmsix_resources; |
101 |
}; |
102 |
|
103 |
static int vtpci_probe(device_t); |
104 |
static int vtpci_attach(device_t); |
105 |
static int vtpci_detach(device_t); |
106 |
static int vtpci_suspend(device_t); |
107 |
static int vtpci_resume(device_t); |
108 |
static int vtpci_shutdown(device_t); |
109 |
static void vtpci_driver_added(device_t, driver_t *); |
110 |
static void vtpci_child_detached(device_t, device_t); |
111 |
static int vtpci_read_ivar(device_t, device_t, int, uintptr_t *); |
112 |
static int vtpci_write_ivar(device_t, device_t, int, uintptr_t); |
113 |
|
114 |
static uint64_t vtpci_negotiate_features(device_t, uint64_t); |
115 |
static int vtpci_with_feature(device_t, uint64_t); |
116 |
static int vtpci_alloc_virtqueues(device_t, int, int, |
117 |
struct vq_alloc_info *); |
118 |
static int vtpci_setup_intr(device_t, enum intr_type); |
119 |
static void vtpci_stop(device_t); |
120 |
static int vtpci_reinit(device_t, uint64_t); |
121 |
static void vtpci_reinit_complete(device_t); |
122 |
static void vtpci_notify_virtqueue(device_t, uint16_t); |
123 |
static uint8_t vtpci_get_status(device_t); |
124 |
static void vtpci_set_status(device_t, uint8_t); |
125 |
static void vtpci_read_dev_config(device_t, bus_size_t, void *, int); |
126 |
static void vtpci_write_dev_config(device_t, bus_size_t, void *, int); |
127 |
|
128 |
static void vtpci_describe_features(struct vtpci_softc *, const char *, |
Lines 59-65
Link Here
|
59 |
static int vtpci_alloc_msix(struct vtpci_common *, int); |
130 |
static void vtpci_probe_and_attach_child(struct vtpci_softc *); |
60 |
static int vtpci_alloc_msi(struct vtpci_common *); |
131 |
|
61 |
static int vtpci_alloc_intr_msix_pervq(struct vtpci_common *); |
132 |
static int vtpci_alloc_msix(struct vtpci_softc *, int); |
62 |
static int vtpci_alloc_intr_msix_shared(struct vtpci_common *); |
133 |
static int vtpci_alloc_msi(struct vtpci_softc *); |
63 |
static int vtpci_alloc_intr_msi(struct vtpci_common *); |
134 |
static int vtpci_alloc_intr_msix_pervq(struct vtpci_softc *); |
64 |
static int vtpci_alloc_intr_intx(struct vtpci_common *); |
135 |
static int vtpci_alloc_intr_msix_shared(struct vtpci_softc *); |
65 |
static int vtpci_alloc_interrupt(struct vtpci_common *, int, int, |
136 |
static int vtpci_alloc_intr_msi(struct vtpci_softc *); |
66 |
-- |
137 |
static int vtpci_alloc_intr_legacy(struct vtpci_softc *); |
|
|
138 |
static int vtpci_alloc_interrupt(struct vtpci_softc *, int, int, |
Lines 67-68
Link Here
|
67 |
static void vtpci_free_interrupt(struct vtpci_common *, |
140 |
static int vtpci_alloc_intr_resources(struct vtpci_softc *); |
68 |
struct vtpci_interrupt *); |
|
|
69 |
-- |
Lines 70-74
Link Here
|
70 |
static void vtpci_free_interrupts(struct vtpci_common *); |
142 |
static int vtpci_setup_legacy_interrupt(struct vtpci_softc *, |
71 |
static void vtpci_free_virtqueues(struct vtpci_common *); |
|
|
72 |
static void vtpci_cleanup_setup_intr_attempt(struct vtpci_common *); |
73 |
static int vtpci_alloc_intr_resources(struct vtpci_common *); |
74 |
static int vtpci_setup_intx_interrupt(struct vtpci_common *, |
75 |
-- |
Line 76
Link Here
|
76 |
static int vtpci_setup_pervq_msix_interrupts(struct vtpci_common *, |
144 |
static int vtpci_setup_pervq_msix_interrupts(struct vtpci_softc *, |
77 |
-- |
|
|
Lines 78-79
Link Here
|
78 |
static int vtpci_set_host_msix_vectors(struct vtpci_common *); |
146 |
static int vtpci_setup_msix_interrupts(struct vtpci_softc *, |
79 |
static int vtpci_setup_msix_interrupts(struct vtpci_common *, |
|
|
80 |
-- |
Lines 81-83
Link Here
|
81 |
static int vtpci_setup_intrs(struct vtpci_common *, enum intr_type); |
148 |
static int vtpci_setup_interrupts(struct vtpci_softc *, enum intr_type); |
82 |
static int vtpci_reinit_virtqueue(struct vtpci_common *, int); |
149 |
|
83 |
static void vtpci_intx_intr(void *); |
150 |
static int vtpci_register_msix_vector(struct vtpci_softc *, int, |
84 |
-- |
151 |
struct vtpci_interrupt *); |
|
|
152 |
static int vtpci_set_host_msix_vectors(struct vtpci_softc *); |
153 |
static int vtpci_reinit_virtqueue(struct vtpci_softc *, int); |
154 |
|
155 |
static void vtpci_free_interrupt(struct vtpci_softc *, |
156 |
struct vtpci_interrupt *); |
157 |
static void vtpci_free_interrupts(struct vtpci_softc *); |
158 |
static void vtpci_free_virtqueues(struct vtpci_softc *); |
159 |
static void vtpci_release_child_resources(struct vtpci_softc *); |
160 |
static void vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *); |
161 |
static void vtpci_reset(struct vtpci_softc *); |
162 |
|
163 |
static void vtpci_select_virtqueue(struct vtpci_softc *, int); |
164 |
|
165 |
static void vtpci_legacy_intr(void *); |
Line 90
Link Here
|
90 |
static void vtpci_setup_sysctl(struct vtpci_common *); |
172 |
#define vtpci_setup_msi_interrupt vtpci_setup_legacy_interrupt |
91 |
-- |
|
|
Line 92
Link Here
|
92 |
#define vtpci_setup_msi_interrupt vtpci_setup_intx_interrupt |
174 |
#define VIRTIO_PCI_CONFIG(_sc) \ |
93 |
-- |
175 |
VIRTIO_PCI_CONFIG_OFF((((_sc)->vtpci_flags & VTPCI_FLAG_MSIX)) != 0) |
Lines 95-97
Link Here
|
95 |
* This module contains two drivers: |
178 |
* I/O port read/write wrappers. |
96 |
* - virtio_pci_legacy (vtpcil) for pre-V1 support |
|
|
97 |
* - virtio_pci_modern (vtpcim) for V1 support |
98 |
-- |
Lines 99-101
Link Here
|
99 |
MODULE_VERSION(virtio_pci, 1); |
180 |
#define vtpci_read_config_1(sc, o) bus_read_1((sc)->vtpci_res, (o)) |
100 |
MODULE_DEPEND(virtio_pci, pci, 1, 1, 1); |
181 |
#define vtpci_read_config_2(sc, o) bus_read_2((sc)->vtpci_res, (o)) |
101 |
MODULE_DEPEND(virtio_pci, virtio, 1, 1, 1); |
182 |
#define vtpci_read_config_4(sc, o) bus_read_4((sc)->vtpci_res, (o)) |
102 |
-- |
183 |
#define vtpci_write_config_1(sc, o, v) bus_write_1((sc)->vtpci_res, (o), (v)) |
|
|
184 |
#define vtpci_write_config_2(sc, o, v) bus_write_2((sc)->vtpci_res, (o), (v)) |
185 |
#define vtpci_write_config_4(sc, o, v) bus_write_4((sc)->vtpci_res, (o), (v)) |
Line 103
Link Here
|
103 |
int vtpci_disable_msix = 0; |
187 |
/* Tunables. */ |
104 |
-- |
188 |
static int vtpci_disable_msix = 0; |
Lines 106-110
Link Here
|
106 |
static uint8_t |
191 |
static device_method_t vtpci_methods[] = { |
107 |
vtpci_read_isr(struct vtpci_common *cn) |
192 |
/* Device interface. */ |
108 |
{ |
193 |
DEVMETHOD(device_probe, vtpci_probe), |
109 |
return (VIRTIO_PCI_READ_ISR(cn->vtpci_dev)); |
194 |
DEVMETHOD(device_attach, vtpci_attach), |
110 |
} |
195 |
DEVMETHOD(device_detach, vtpci_detach), |
111 |
-- |
196 |
DEVMETHOD(device_suspend, vtpci_suspend), |
|
|
197 |
DEVMETHOD(device_resume, vtpci_resume), |
198 |
DEVMETHOD(device_shutdown, vtpci_shutdown), |
Lines 112-116
Link Here
|
112 |
static uint16_t |
200 |
/* Bus interface. */ |
113 |
vtpci_get_vq_size(struct vtpci_common *cn, int idx) |
201 |
DEVMETHOD(bus_driver_added, vtpci_driver_added), |
114 |
{ |
202 |
DEVMETHOD(bus_child_detached, vtpci_child_detached), |
115 |
return (VIRTIO_PCI_GET_VQ_SIZE(cn->vtpci_dev, idx)); |
203 |
DEVMETHOD(bus_read_ivar, vtpci_read_ivar), |
116 |
} |
204 |
DEVMETHOD(bus_write_ivar, vtpci_write_ivar), |
117 |
-- |
|
|
Lines 118-122
Link Here
|
118 |
static bus_size_t |
206 |
/* VirtIO bus interface. */ |
119 |
vtpci_get_vq_notify_off(struct vtpci_common *cn, int idx) |
207 |
DEVMETHOD(virtio_bus_negotiate_features, vtpci_negotiate_features), |
120 |
{ |
208 |
DEVMETHOD(virtio_bus_with_feature, vtpci_with_feature), |
121 |
return (VIRTIO_PCI_GET_VQ_NOTIFY_OFF(cn->vtpci_dev, idx)); |
209 |
DEVMETHOD(virtio_bus_alloc_virtqueues, vtpci_alloc_virtqueues), |
122 |
} |
210 |
DEVMETHOD(virtio_bus_setup_intr, vtpci_setup_intr), |
123 |
-- |
211 |
DEVMETHOD(virtio_bus_stop, vtpci_stop), |
|
|
212 |
DEVMETHOD(virtio_bus_reinit, vtpci_reinit), |
213 |
DEVMETHOD(virtio_bus_reinit_complete, vtpci_reinit_complete), |
214 |
DEVMETHOD(virtio_bus_notify_vq, vtpci_notify_virtqueue), |
215 |
DEVMETHOD(virtio_bus_read_device_config, vtpci_read_dev_config), |
216 |
DEVMETHOD(virtio_bus_write_device_config, vtpci_write_dev_config), |
Lines 124-128
Link Here
|
124 |
static void |
218 |
DEVMETHOD_END |
125 |
vtpci_set_vq(struct vtpci_common *cn, struct virtqueue *vq) |
219 |
}; |
126 |
{ |
|
|
127 |
VIRTIO_PCI_SET_VQ(cn->vtpci_dev, vq); |
128 |
} |
129 |
-- |
Lines 130-134
Link Here
|
130 |
static void |
221 |
static driver_t vtpci_driver = { |
131 |
vtpci_disable_vq(struct vtpci_common *cn, int idx) |
222 |
"virtio_pci", |
132 |
{ |
223 |
vtpci_methods, |
133 |
VIRTIO_PCI_DISABLE_VQ(cn->vtpci_dev, idx); |
224 |
sizeof(struct vtpci_softc) |
134 |
} |
225 |
}; |
135 |
-- |
|
|
Line 136
Link Here
|
|
|
227 |
devclass_t vtpci_devclass; |
228 |
|
229 |
DRIVER_MODULE(virtio_pci, pci, vtpci_driver, vtpci_devclass, 0, 0); |
230 |
MODULE_VERSION(virtio_pci, 1); |
231 |
MODULE_DEPEND(virtio_pci, pci, 1, 1, 1); |
232 |
MODULE_DEPEND(virtio_pci, virtio, 1, 1, 1); |
233 |
|
Line 137
Link Here
|
137 |
vtpci_register_cfg_msix(struct vtpci_common *cn, struct vtpci_interrupt *intr) |
235 |
vtpci_probe(device_t dev) |
138 |
-- |
|
|
Line 139
Link Here
|
139 |
return (VIRTIO_PCI_REGISTER_CFG_MSIX(cn->vtpci_dev, intr)); |
237 |
char desc[36]; |
140 |
-- |
238 |
const char *name; |
|
|
239 |
|
240 |
if (pci_get_vendor(dev) != VIRTIO_PCI_VENDORID) |
241 |
return (ENXIO); |
242 |
|
243 |
if (pci_get_device(dev) < VIRTIO_PCI_DEVICEID_MIN || |
244 |
pci_get_device(dev) > VIRTIO_PCI_DEVICEID_MAX) |
245 |
return (ENXIO); |
246 |
|
247 |
if (pci_get_revid(dev) != VIRTIO_PCI_ABI_VERSION) |
248 |
return (ENXIO); |
249 |
|
250 |
name = virtio_device_name(pci_get_subdevice(dev)); |
251 |
if (name == NULL) |
252 |
name = "Unknown"; |
253 |
|
254 |
snprintf(desc, sizeof(desc), "VirtIO PCI %s adapter", name); |
255 |
device_set_desc_copy(dev, desc); |
256 |
|
257 |
return (BUS_PROBE_DEFAULT); |
Lines 143-144
Link Here
|
143 |
vtpci_register_vq_msix(struct vtpci_common *cn, int idx, |
261 |
vtpci_attach(device_t dev) |
144 |
struct vtpci_interrupt *intr) |
|
|
145 |
-- |
Lines 146-147
Link Here
|
146 |
return (VIRTIO_PCI_REGISTER_VQ_MSIX(cn->vtpci_dev, idx, intr)); |
263 |
struct vtpci_softc *sc; |
147 |
} |
264 |
device_t child; |
148 |
-- |
265 |
int rid; |
Lines 149-151
Link Here
|
149 |
void |
267 |
sc = device_get_softc(dev); |
150 |
vtpci_init(struct vtpci_common *cn, device_t dev, bool modern) |
268 |
sc->vtpci_dev = dev; |
151 |
{ |
|
|
152 |
-- |
Lines 153-154
Link Here
|
153 |
cn->vtpci_dev = dev; |
|
|
154 |
|
Lines 157-158
Link Here
|
157 |
if (modern) |
272 |
rid = PCIR_BAR(0); |
158 |
cn->vtpci_flags |= VTPCI_FLAG_MODERN; |
273 |
sc->vtpci_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, |
159 |
-- |
274 |
RF_ACTIVE); |
|
|
275 |
if (sc->vtpci_res == NULL) { |
276 |
device_printf(dev, "cannot map I/O space\n"); |
277 |
return (ENXIO); |
278 |
} |
279 |
|
Lines 160-162
Link Here
|
160 |
cn->vtpci_flags |= VTPCI_FLAG_NO_MSI; |
281 |
sc->vtpci_flags |= VTPCI_FLAG_NO_MSI; |
161 |
if (pci_find_cap(dev, PCIY_MSIX, NULL) != 0) |
|
|
162 |
cn->vtpci_flags |= VTPCI_FLAG_NO_MSIX; |
163 |
-- |
Lines 164-165
Link Here
|
164 |
vtpci_setup_sysctl(cn); |
283 |
if (pci_find_cap(dev, PCIY_MSIX, NULL) == 0) { |
165 |
} |
284 |
rid = PCIR_BAR(1); |
166 |
-- |
285 |
sc->vtpci_msix_res = bus_alloc_resource_any(dev, |
|
|
286 |
SYS_RES_MEMORY, &rid, RF_ACTIVE); |
287 |
} |
Lines 167-170
Link Here
|
167 |
int |
289 |
if (sc->vtpci_msix_res == NULL) |
168 |
vtpci_add_child(struct vtpci_common *cn) |
290 |
sc->vtpci_flags |= VTPCI_FLAG_NO_MSIX; |
169 |
{ |
|
|
170 |
device_t dev, child; |
171 |
-- |
Line 172
Link Here
|
172 |
dev = cn->vtpci_dev; |
292 |
vtpci_reset(sc); |
173 |
-- |
|
|
Lines 174-175
Link Here
|
174 |
child = device_add_child(dev, NULL, -1); |
294 |
/* Tell the host we've noticed this device. */ |
175 |
if (child == NULL) { |
295 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); |
176 |
-- |
296 |
|
|
|
297 |
if ((child = device_add_child(dev, NULL, -1)) == NULL) { |
Line 177
Link Here
|
|
|
299 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); |
300 |
vtpci_detach(dev); |
Line 180
Link Here
|
180 |
cn->vtpci_child_dev = child; |
304 |
sc->vtpci_child_dev = child; |
181 |
-- |
305 |
vtpci_probe_and_attach_child(sc); |
Lines 185-186
Link Here
|
185 |
int |
310 |
static int |
186 |
vtpci_delete_child(struct vtpci_common *cn) |
311 |
vtpci_detach(device_t dev) |
187 |
-- |
|
|
Line 188
Link Here
|
188 |
device_t dev, child; |
313 |
struct vtpci_softc *sc; |
189 |
-- |
314 |
device_t child; |
Line 191
Link Here
|
191 |
dev = cn->vtpci_dev; |
317 |
sc = device_get_softc(dev); |
192 |
-- |
|
|
Lines 193-194
Link Here
|
193 |
child = cn->vtpci_child_dev; |
319 |
if ((child = sc->vtpci_child_dev) != NULL) { |
194 |
if (child != NULL) { |
|
|
195 |
-- |
Line 198
Link Here
|
198 |
cn->vtpci_child_dev = NULL; |
323 |
sc->vtpci_child_dev = NULL; |
199 |
-- |
|
|
Line 201
Link Here
|
|
|
326 |
vtpci_reset(sc); |
327 |
|
328 |
if (sc->vtpci_msix_res != NULL) { |
329 |
bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(1), |
330 |
sc->vtpci_msix_res); |
331 |
sc->vtpci_msix_res = NULL; |
332 |
} |
333 |
|
334 |
if (sc->vtpci_res != NULL) { |
335 |
bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), |
336 |
sc->vtpci_res); |
337 |
sc->vtpci_res = NULL; |
338 |
} |
339 |
|
Lines 204-205
Link Here
|
204 |
void |
343 |
static int |
205 |
vtpci_child_detached(struct vtpci_common *cn) |
344 |
vtpci_suspend(device_t dev) |
206 |
-- |
|
|
Lines 208-212
Link Here
|
208 |
vtpci_release_child_resources(cn); |
347 |
return (bus_generic_suspend(dev)); |
209 |
|
|
|
210 |
cn->vtpci_child_feat_desc = NULL; |
211 |
cn->vtpci_host_features = 0; |
212 |
cn->vtpci_features = 0; |
213 |
-- |
Lines 215-216
Link Here
|
215 |
int |
350 |
static int |
216 |
vtpci_reinit(struct vtpci_common *cn) |
351 |
vtpci_resume(device_t dev) |
217 |
-- |
|
|
Line 218
Link Here
|
218 |
int idx, error; |
|
|
Lines 220-224
Link Here
|
220 |
for (idx = 0; idx < cn->vtpci_nvqs; idx++) { |
354 |
return (bus_generic_resume(dev)); |
221 |
error = vtpci_reinit_virtqueue(cn, idx); |
355 |
} |
222 |
if (error) |
|
|
223 |
return (error); |
224 |
} |
225 |
-- |
Lines 226-230
Link Here
|
226 |
if (vtpci_is_msix_enabled(cn)) { |
357 |
static int |
227 |
error = vtpci_set_host_msix_vectors(cn); |
358 |
vtpci_shutdown(device_t dev) |
228 |
if (error) |
359 |
{ |
229 |
return (error); |
|
|
230 |
} |
231 |
-- |
Line 232
Link Here
|
|
|
361 |
(void) bus_generic_shutdown(dev); |
362 |
/* Forcibly stop the host device. */ |
363 |
vtpci_stop(dev); |
364 |
|
Lines 236-237
Link Here
|
236 |
vtpci_describe_features(struct vtpci_common *cn, const char *msg, |
369 |
vtpci_driver_added(device_t dev, driver_t *driver) |
237 |
uint64_t features) |
|
|
238 |
-- |
Line 239
Link Here
|
239 |
device_t dev, child; |
371 |
struct vtpci_softc *sc; |
240 |
-- |
|
|
Lines 241-242
Link Here
|
241 |
dev = cn->vtpci_dev; |
373 |
sc = device_get_softc(dev); |
242 |
child = cn->vtpci_child_dev; |
|
|
243 |
-- |
Lines 244-247
Link Here
|
244 |
if (device_is_attached(child) || bootverbose == 0) |
375 |
vtpci_probe_and_attach_child(sc); |
245 |
return; |
|
|
246 |
|
247 |
virtio_describe(dev, msg, features, cn->vtpci_child_feat_desc); |
248 |
-- |
Lines 250-252
Link Here
|
250 |
uint64_t |
378 |
static void |
251 |
vtpci_negotiate_features(struct vtpci_common *cn, |
379 |
vtpci_child_detached(device_t dev, device_t child) |
252 |
uint64_t child_features, uint64_t host_features) |
|
|
253 |
-- |
Line 254
Link Here
|
254 |
uint64_t features; |
381 |
struct vtpci_softc *sc; |
255 |
-- |
|
|
Lines 256-257
Link Here
|
256 |
cn->vtpci_host_features = host_features; |
383 |
sc = device_get_softc(dev); |
257 |
vtpci_describe_features(cn, "host", host_features); |
|
|
258 |
-- |
Lines 259-269
Link Here
|
259 |
/* |
385 |
vtpci_reset(sc); |
260 |
* Limit negotiated features to what the driver, virtqueue, and |
386 |
vtpci_release_child_resources(sc); |
261 |
* host all support. |
|
|
262 |
*/ |
263 |
features = host_features & child_features; |
264 |
features = virtio_filter_transport_features(features); |
265 |
|
266 |
cn->vtpci_features = features; |
267 |
vtpci_describe_features(cn, "negotiated", features); |
268 |
|
269 |
return (features); |
270 |
-- |
Lines 272-273
Link Here
|
272 |
int |
389 |
static int |
273 |
vtpci_with_feature(struct vtpci_common *cn, uint64_t feature) |
390 |
vtpci_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) |
274 |
-- |
|
|
Lines 275-276
Link Here
|
275 |
return ((cn->vtpci_features & feature) != 0); |
392 |
struct vtpci_softc *sc; |
276 |
} |
|
|
277 |
-- |
Lines 278-282
Link Here
|
278 |
int |
394 |
sc = device_get_softc(dev); |
279 |
vtpci_read_ivar(struct vtpci_common *cn, int index, uintptr_t *result) |
|
|
280 |
{ |
281 |
device_t dev; |
282 |
int error; |
283 |
-- |
Lines 284-285
Link Here
|
284 |
dev = cn->vtpci_dev; |
396 |
if (sc->vtpci_child_dev != child) |
285 |
error = 0; |
397 |
return (ENOENT); |
286 |
-- |
|
|
Line 288
Link Here
|
|
|
400 |
case VIRTIO_IVAR_DEVTYPE: |
Lines 300-302
Link Here
|
300 |
case VIRTIO_IVAR_MODERN: |
|
|
301 |
*result = vtpci_is_modern(cn); |
302 |
break; |
Line 304
Link Here
|
304 |
error = ENOENT; |
414 |
return (ENOENT); |
305 |
-- |
|
|
Line 307
Link Here
|
307 |
return (error); |
417 |
return (0); |
308 |
-- |
|
|
Lines 310-311
Link Here
|
310 |
int |
420 |
static int |
311 |
vtpci_write_ivar(struct vtpci_common *cn, int index, uintptr_t value) |
421 |
vtpci_write_ivar(device_t dev, device_t child, int index, uintptr_t value) |
312 |
-- |
|
|
Line 313
Link Here
|
313 |
int error; |
423 |
struct vtpci_softc *sc; |
314 |
-- |
|
|
Line 315
Link Here
|
315 |
error = 0; |
425 |
sc = device_get_softc(dev); |
316 |
-- |
|
|
Line 317
Link Here
|
|
|
427 |
if (sc->vtpci_child_dev != child) |
428 |
return (ENOENT); |
429 |
|
Line 319
Link Here
|
319 |
cn->vtpci_child_feat_desc = (void *) value; |
432 |
sc->vtpci_child_feat_desc = (void *) value; |
320 |
-- |
|
|
Line 322
Link Here
|
322 |
error = ENOENT; |
435 |
return (ENOENT); |
323 |
-- |
|
|
Line 325
Link Here
|
325 |
return (error); |
438 |
return (0); |
326 |
-- |
|
|
Lines 328-330
Link Here
|
328 |
int |
441 |
static uint64_t |
329 |
vtpci_alloc_virtqueues(struct vtpci_common *cn, int flags, int nvqs, |
442 |
vtpci_negotiate_features(device_t dev, uint64_t child_features) |
330 |
struct vq_alloc_info *vq_info) |
|
|
331 |
-- |
Lines 332-333
Link Here
|
332 |
device_t dev; |
444 |
struct vtpci_softc *sc; |
333 |
int idx, align, error; |
445 |
uint64_t host_features, features; |
334 |
-- |
|
|
Line 335
Link Here
|
335 |
dev = cn->vtpci_dev; |
447 |
sc = device_get_softc(dev); |
336 |
-- |
|
|
Line 337
Link Here
|
|
|
449 |
host_features = vtpci_read_config_4(sc, VIRTIO_PCI_HOST_FEATURES); |
450 |
vtpci_describe_features(sc, "host", host_features); |
451 |
|
Lines 338-340
Link Here
|
338 |
* This is VIRTIO_PCI_VRING_ALIGN from legacy VirtIO. In modern VirtIO, |
453 |
* Limit negotiated features to what the driver, virtqueue, and |
339 |
* the tables do not have to be allocated contiguously, but we do so |
454 |
* host all support. |
340 |
* anyways. |
|
|
341 |
-- |
Line 342
Link Here
|
342 |
align = 4096; |
456 |
features = host_features & child_features; |
343 |
-- |
457 |
features = virtqueue_filter_features(features); |
|
|
458 |
sc->vtpci_features = features; |
Line 344
Link Here
|
344 |
if (cn->vtpci_nvqs != 0) |
460 |
vtpci_describe_features(sc, "negotiated", features); |
345 |
-- |
461 |
vtpci_write_config_4(sc, VIRTIO_PCI_GUEST_FEATURES, features); |
|
|
462 |
|
463 |
return (features); |
464 |
} |
465 |
|
466 |
static int |
467 |
vtpci_with_feature(device_t dev, uint64_t feature) |
468 |
{ |
469 |
struct vtpci_softc *sc; |
470 |
|
471 |
sc = device_get_softc(dev); |
472 |
|
473 |
return ((sc->vtpci_features & feature) != 0); |
474 |
} |
475 |
|
476 |
static int |
477 |
vtpci_alloc_virtqueues(device_t dev, int flags, int nvqs, |
478 |
struct vq_alloc_info *vq_info) |
479 |
{ |
480 |
struct vtpci_softc *sc; |
481 |
struct virtqueue *vq; |
482 |
struct vtpci_virtqueue *vqx; |
483 |
struct vq_alloc_info *info; |
484 |
int idx, error; |
485 |
uint16_t size; |
486 |
|
487 |
sc = device_get_softc(dev); |
488 |
|
489 |
if (sc->vtpci_nvqs != 0) |
Line 349
Link Here
|
349 |
cn->vtpci_vqs = malloc(nvqs * sizeof(struct vtpci_virtqueue), |
494 |
sc->vtpci_vqs = malloc(nvqs * sizeof(struct vtpci_virtqueue), |
350 |
-- |
|
|
Line 351
Link Here
|
351 |
if (cn->vtpci_vqs == NULL) |
496 |
if (sc->vtpci_vqs == NULL) |
352 |
-- |
|
|
Lines 355-361
Link Here
|
355 |
struct vtpci_virtqueue *vqx; |
500 |
vqx = &sc->vtpci_vqs[idx]; |
356 |
struct vq_alloc_info *info; |
|
|
357 |
struct virtqueue *vq; |
358 |
bus_size_t notify_offset; |
359 |
uint16_t size; |
360 |
|
361 |
vqx = &cn->vtpci_vqs[idx]; |
362 |
-- |
Lines 364-365
Link Here
|
364 |
size = vtpci_get_vq_size(cn, idx); |
503 |
vtpci_select_virtqueue(sc, idx); |
365 |
notify_offset = vtpci_get_vq_notify_off(cn, idx); |
504 |
size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); |
366 |
-- |
|
|
Line 367
Link Here
|
367 |
error = virtqueue_alloc(dev, idx, size, notify_offset, align, |
506 |
error = virtqueue_alloc(dev, idx, size, VIRTIO_PCI_VRING_ALIGN, |
368 |
-- |
|
|
Line 375
Link Here
|
375 |
vtpci_set_vq(cn, vq); |
514 |
vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, |
376 |
-- |
515 |
virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); |
Line 380
Link Here
|
380 |
cn->vtpci_nvqs++; |
520 |
sc->vtpci_nvqs++; |
381 |
-- |
|
|
Line 384
Link Here
|
384 |
vtpci_free_virtqueues(cn); |
524 |
vtpci_free_virtqueues(sc); |
385 |
-- |
|
|
Line 390
Link Here
|
390 |
vtpci_alloc_msix(struct vtpci_common *cn, int nvectors) |
530 |
vtpci_setup_intr(device_t dev, enum intr_type type) |
391 |
-- |
|
|
Line 392
Link Here
|
|
|
532 |
struct vtpci_softc *sc; |
533 |
int attempt, error; |
534 |
|
535 |
sc = device_get_softc(dev); |
536 |
|
537 |
for (attempt = 0; attempt < 5; attempt++) { |
538 |
/* |
539 |
* Start with the most desirable interrupt configuration and |
540 |
* fallback towards less desirable ones. |
541 |
*/ |
542 |
switch (attempt) { |
543 |
case 0: |
544 |
error = vtpci_alloc_intr_msix_pervq(sc); |
545 |
break; |
546 |
case 1: |
547 |
error = vtpci_alloc_intr_msix_shared(sc); |
548 |
break; |
549 |
case 2: |
550 |
error = vtpci_alloc_intr_msi(sc); |
551 |
break; |
552 |
case 3: |
553 |
error = vtpci_alloc_intr_legacy(sc); |
554 |
break; |
555 |
default: |
556 |
device_printf(dev, |
557 |
"exhausted all interrupt allocation attempts\n"); |
558 |
return (ENXIO); |
559 |
} |
560 |
|
561 |
if (error == 0 && vtpci_setup_interrupts(sc, type) == 0) |
562 |
break; |
563 |
|
564 |
vtpci_cleanup_setup_intr_attempt(sc); |
565 |
} |
566 |
|
567 |
if (bootverbose) { |
568 |
if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) |
569 |
device_printf(dev, "using legacy interrupt\n"); |
570 |
else if (sc->vtpci_flags & VTPCI_FLAG_MSI) |
571 |
device_printf(dev, "using MSI interrupt\n"); |
572 |
else if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) |
573 |
device_printf(dev, "using shared MSIX interrupts\n"); |
574 |
else |
575 |
device_printf(dev, "using per VQ MSIX interrupts\n"); |
576 |
} |
577 |
|
578 |
return (0); |
579 |
} |
580 |
|
581 |
static void |
582 |
vtpci_stop(device_t dev) |
583 |
{ |
584 |
|
585 |
vtpci_reset(device_get_softc(dev)); |
586 |
} |
587 |
|
588 |
static int |
589 |
vtpci_reinit(device_t dev, uint64_t features) |
590 |
{ |
591 |
struct vtpci_softc *sc; |
592 |
int idx, error; |
593 |
|
594 |
sc = device_get_softc(dev); |
595 |
|
596 |
/* |
597 |
* Redrive the device initialization. This is a bit of an abuse of |
598 |
* the specification, but VirtualBox, QEMU/KVM, and BHyVe seem to |
599 |
* play nice. |
600 |
* |
601 |
* We do not allow the host device to change from what was originally |
602 |
* negotiated beyond what the guest driver changed. MSIX state should |
603 |
* not change, number of virtqueues and their size remain the same, etc. |
604 |
* This will need to be rethought when we want to support migration. |
605 |
*/ |
606 |
|
607 |
if (vtpci_get_status(dev) != VIRTIO_CONFIG_STATUS_RESET) |
608 |
vtpci_stop(dev); |
609 |
|
610 |
/* |
611 |
* Quickly drive the status through ACK and DRIVER. The device |
612 |
* does not become usable again until vtpci_reinit_complete(). |
613 |
*/ |
614 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); |
615 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); |
616 |
|
617 |
vtpci_negotiate_features(dev, features); |
618 |
|
619 |
for (idx = 0; idx < sc->vtpci_nvqs; idx++) { |
620 |
error = vtpci_reinit_virtqueue(sc, idx); |
621 |
if (error) |
622 |
return (error); |
623 |
} |
624 |
|
625 |
if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { |
626 |
error = vtpci_set_host_msix_vectors(sc); |
627 |
if (error) |
628 |
return (error); |
629 |
} |
630 |
|
631 |
return (0); |
632 |
} |
633 |
|
634 |
static void |
635 |
vtpci_reinit_complete(device_t dev) |
636 |
{ |
637 |
|
638 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); |
639 |
} |
640 |
|
641 |
static void |
642 |
vtpci_notify_virtqueue(device_t dev, uint16_t queue) |
643 |
{ |
644 |
struct vtpci_softc *sc; |
645 |
|
646 |
sc = device_get_softc(dev); |
647 |
|
648 |
vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_NOTIFY, queue); |
649 |
} |
650 |
|
651 |
static uint8_t |
652 |
vtpci_get_status(device_t dev) |
653 |
{ |
654 |
struct vtpci_softc *sc; |
655 |
|
656 |
sc = device_get_softc(dev); |
657 |
|
658 |
return (vtpci_read_config_1(sc, VIRTIO_PCI_STATUS)); |
659 |
} |
660 |
|
661 |
static void |
662 |
vtpci_set_status(device_t dev, uint8_t status) |
663 |
{ |
664 |
struct vtpci_softc *sc; |
665 |
|
666 |
sc = device_get_softc(dev); |
667 |
|
668 |
if (status != VIRTIO_CONFIG_STATUS_RESET) |
669 |
status |= vtpci_get_status(dev); |
670 |
|
671 |
vtpci_write_config_1(sc, VIRTIO_PCI_STATUS, status); |
672 |
} |
673 |
|
674 |
static void |
675 |
vtpci_read_dev_config(device_t dev, bus_size_t offset, |
676 |
void *dst, int length) |
677 |
{ |
678 |
struct vtpci_softc *sc; |
679 |
bus_size_t off; |
680 |
uint8_t *d; |
681 |
int size; |
682 |
|
683 |
sc = device_get_softc(dev); |
684 |
off = VIRTIO_PCI_CONFIG(sc) + offset; |
685 |
|
686 |
for (d = dst; length > 0; d += size, off += size, length -= size) { |
687 |
if (length >= 4) { |
688 |
size = 4; |
689 |
*(uint32_t *)d = vtpci_read_config_4(sc, off); |
690 |
} else if (length >= 2) { |
691 |
size = 2; |
692 |
*(uint16_t *)d = vtpci_read_config_2(sc, off); |
693 |
} else { |
694 |
size = 1; |
695 |
*d = vtpci_read_config_1(sc, off); |
696 |
} |
697 |
} |
698 |
} |
699 |
|
700 |
static void |
701 |
vtpci_write_dev_config(device_t dev, bus_size_t offset, |
702 |
void *src, int length) |
703 |
{ |
704 |
struct vtpci_softc *sc; |
705 |
bus_size_t off; |
706 |
uint8_t *s; |
707 |
int size; |
708 |
|
709 |
sc = device_get_softc(dev); |
710 |
off = VIRTIO_PCI_CONFIG(sc) + offset; |
711 |
|
712 |
for (s = src; length > 0; s += size, off += size, length -= size) { |
713 |
if (length >= 4) { |
714 |
size = 4; |
715 |
vtpci_write_config_4(sc, off, *(uint32_t *)s); |
716 |
} else if (length >= 2) { |
717 |
size = 2; |
718 |
vtpci_write_config_2(sc, off, *(uint16_t *)s); |
719 |
} else { |
720 |
size = 1; |
721 |
vtpci_write_config_1(sc, off, *s); |
722 |
} |
723 |
} |
724 |
} |
725 |
|
726 |
static void |
727 |
vtpci_describe_features(struct vtpci_softc *sc, const char *msg, |
728 |
uint64_t features) |
729 |
{ |
730 |
device_t dev, child; |
731 |
|
732 |
dev = sc->vtpci_dev; |
733 |
child = sc->vtpci_child_dev; |
734 |
|
735 |
if (device_is_attached(child) || bootverbose == 0) |
736 |
return; |
737 |
|
738 |
virtio_describe(dev, msg, features, sc->vtpci_child_feat_desc); |
739 |
} |
740 |
|
741 |
static void |
742 |
vtpci_probe_and_attach_child(struct vtpci_softc *sc) |
743 |
{ |
744 |
device_t dev, child; |
745 |
|
746 |
dev = sc->vtpci_dev; |
747 |
child = sc->vtpci_child_dev; |
748 |
|
749 |
if (child == NULL) |
750 |
return; |
751 |
|
752 |
if (device_get_state(child) != DS_NOTPRESENT) |
753 |
return; |
754 |
|
755 |
if (device_probe(child) != 0) |
756 |
return; |
757 |
|
758 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); |
759 |
if (device_attach(child) != 0) { |
760 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); |
761 |
vtpci_reset(sc); |
762 |
vtpci_release_child_resources(sc); |
763 |
/* Reset status for future attempt. */ |
764 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); |
765 |
} else { |
766 |
vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); |
767 |
VIRTIO_ATTACH_COMPLETED(child); |
768 |
} |
769 |
} |
770 |
|
771 |
static int |
772 |
vtpci_alloc_msix(struct vtpci_softc *sc, int nvectors) |
773 |
{ |
Line 395
Link Here
|
395 |
dev = cn->vtpci_dev; |
777 |
dev = sc->vtpci_dev; |
396 |
-- |
|
|
Line 406
Link Here
|
406 |
cn->vtpci_nmsix_resources = required; |
788 |
sc->vtpci_nmsix_resources = required; |
407 |
-- |
|
|
Line 416
Link Here
|
416 |
vtpci_alloc_msi(struct vtpci_common *cn) |
798 |
vtpci_alloc_msi(struct vtpci_softc *sc) |
417 |
-- |
|
|
Line 421
Link Here
|
421 |
dev = cn->vtpci_dev; |
803 |
dev = sc->vtpci_dev; |
422 |
-- |
|
|
Line 438
Link Here
|
438 |
vtpci_alloc_intr_msix_pervq(struct vtpci_common *cn) |
820 |
vtpci_alloc_intr_msix_pervq(struct vtpci_softc *sc) |
439 |
-- |
|
|
Line 442
Link Here
|
442 |
if (vtpci_disable_msix != 0 || cn->vtpci_flags & VTPCI_FLAG_NO_MSIX) |
824 |
if (vtpci_disable_msix != 0 || |
443 |
-- |
825 |
sc->vtpci_flags & VTPCI_FLAG_NO_MSIX) |
Lines 445-446
Link Here
|
445 |
for (nvectors = 0, i = 0; i < cn->vtpci_nvqs; i++) { |
828 |
for (nvectors = 0, i = 0; i < sc->vtpci_nvqs; i++) { |
446 |
if (cn->vtpci_vqs[i].vtv_no_intr == 0) |
829 |
if (sc->vtpci_vqs[i].vtv_no_intr == 0) |
447 |
-- |
|
|
Line 450
Link Here
|
450 |
error = vtpci_alloc_msix(cn, nvectors); |
833 |
error = vtpci_alloc_msix(sc, nvectors); |
451 |
-- |
|
|
Line 454
Link Here
|
454 |
cn->vtpci_flags |= VTPCI_FLAG_MSIX; |
837 |
sc->vtpci_flags |= VTPCI_FLAG_MSIX; |
455 |
-- |
|
|
Line 460
Link Here
|
460 |
vtpci_alloc_intr_msix_shared(struct vtpci_common *cn) |
843 |
vtpci_alloc_intr_msix_shared(struct vtpci_softc *sc) |
461 |
-- |
|
|
Line 464
Link Here
|
464 |
if (vtpci_disable_msix != 0 || cn->vtpci_flags & VTPCI_FLAG_NO_MSIX) |
847 |
if (vtpci_disable_msix != 0 || |
465 |
-- |
848 |
sc->vtpci_flags & VTPCI_FLAG_NO_MSIX) |
Line 467
Link Here
|
467 |
error = vtpci_alloc_msix(cn, 1); |
851 |
error = vtpci_alloc_msix(sc, 1); |
468 |
-- |
|
|
Line 471
Link Here
|
471 |
cn->vtpci_flags |= VTPCI_FLAG_MSIX | VTPCI_FLAG_SHARED_MSIX; |
855 |
sc->vtpci_flags |= VTPCI_FLAG_MSIX | VTPCI_FLAG_SHARED_MSIX; |
472 |
-- |
|
|
Line 477
Link Here
|
477 |
vtpci_alloc_intr_msi(struct vtpci_common *cn) |
861 |
vtpci_alloc_intr_msi(struct vtpci_softc *sc) |
478 |
-- |
|
|
Line 482
Link Here
|
482 |
if (cn->vtpci_flags & VTPCI_FLAG_NO_MSI) |
866 |
if (sc->vtpci_flags & VTPCI_FLAG_NO_MSI) |
483 |
-- |
|
|
Line 485
Link Here
|
485 |
error = vtpci_alloc_msi(cn); |
869 |
error = vtpci_alloc_msi(sc); |
486 |
-- |
|
|
Line 489
Link Here
|
489 |
cn->vtpci_flags |= VTPCI_FLAG_MSI; |
873 |
sc->vtpci_flags |= VTPCI_FLAG_MSI; |
490 |
-- |
|
|
Line 495
Link Here
|
495 |
vtpci_alloc_intr_intx(struct vtpci_common *cn) |
879 |
vtpci_alloc_intr_legacy(struct vtpci_softc *sc) |
496 |
-- |
|
|
Line 498
Link Here
|
498 |
cn->vtpci_flags |= VTPCI_FLAG_INTX; |
882 |
sc->vtpci_flags |= VTPCI_FLAG_LEGACY; |
499 |
-- |
|
|
Line 504
Link Here
|
504 |
vtpci_alloc_interrupt(struct vtpci_common *cn, int rid, int flags, |
888 |
vtpci_alloc_interrupt(struct vtpci_softc *sc, int rid, int flags, |
505 |
-- |
|
|
Line 509
Link Here
|
509 |
irq = bus_alloc_resource_any(cn->vtpci_dev, SYS_RES_IRQ, &rid, flags); |
893 |
irq = bus_alloc_resource_any(sc->vtpci_dev, SYS_RES_IRQ, &rid, flags); |
510 |
-- |
|
|
Lines 519-607
Link Here
|
519 |
static void |
|
|
520 |
vtpci_free_interrupt(struct vtpci_common *cn, struct vtpci_interrupt *intr) |
521 |
{ |
522 |
device_t dev; |
523 |
|
524 |
dev = cn->vtpci_dev; |
525 |
|
526 |
if (intr->vti_handler != NULL) { |
527 |
bus_teardown_intr(dev, intr->vti_irq, intr->vti_handler); |
528 |
intr->vti_handler = NULL; |
529 |
} |
530 |
|
531 |
if (intr->vti_irq != NULL) { |
532 |
bus_release_resource(dev, SYS_RES_IRQ, intr->vti_rid, |
533 |
intr->vti_irq); |
534 |
intr->vti_irq = NULL; |
535 |
intr->vti_rid = -1; |
536 |
} |
537 |
} |
538 |
|
539 |
static void |
540 |
vtpci_free_interrupts(struct vtpci_common *cn) |
541 |
{ |
542 |
struct vtpci_interrupt *intr; |
543 |
int i, nvq_intrs; |
544 |
|
545 |
vtpci_free_interrupt(cn, &cn->vtpci_device_interrupt); |
546 |
|
547 |
if (cn->vtpci_nmsix_resources != 0) { |
548 |
nvq_intrs = cn->vtpci_nmsix_resources - 1; |
549 |
cn->vtpci_nmsix_resources = 0; |
550 |
|
551 |
if ((intr = cn->vtpci_msix_vq_interrupts) != NULL) { |
552 |
for (i = 0; i < nvq_intrs; i++, intr++) |
553 |
vtpci_free_interrupt(cn, intr); |
554 |
|
555 |
free(cn->vtpci_msix_vq_interrupts, M_DEVBUF); |
556 |
cn->vtpci_msix_vq_interrupts = NULL; |
557 |
} |
558 |
} |
559 |
|
560 |
if (cn->vtpci_flags & (VTPCI_FLAG_MSI | VTPCI_FLAG_MSIX)) |
561 |
pci_release_msi(cn->vtpci_dev); |
562 |
|
563 |
cn->vtpci_flags &= ~VTPCI_FLAG_ITYPE_MASK; |
564 |
} |
565 |
|
566 |
static void |
567 |
vtpci_free_virtqueues(struct vtpci_common *cn) |
568 |
{ |
569 |
struct vtpci_virtqueue *vqx; |
570 |
int idx; |
571 |
|
572 |
for (idx = 0; idx < cn->vtpci_nvqs; idx++) { |
573 |
vtpci_disable_vq(cn, idx); |
574 |
|
575 |
vqx = &cn->vtpci_vqs[idx]; |
576 |
virtqueue_free(vqx->vtv_vq); |
577 |
vqx->vtv_vq = NULL; |
578 |
} |
579 |
|
580 |
free(cn->vtpci_vqs, M_DEVBUF); |
581 |
cn->vtpci_vqs = NULL; |
582 |
cn->vtpci_nvqs = 0; |
583 |
} |
584 |
|
585 |
void |
586 |
vtpci_release_child_resources(struct vtpci_common *cn) |
587 |
{ |
588 |
|
589 |
vtpci_free_interrupts(cn); |
590 |
vtpci_free_virtqueues(cn); |
591 |
} |
592 |
|
593 |
static void |
594 |
vtpci_cleanup_setup_intr_attempt(struct vtpci_common *cn) |
595 |
{ |
596 |
int idx; |
597 |
|
598 |
if (cn->vtpci_flags & VTPCI_FLAG_MSIX) { |
599 |
vtpci_register_cfg_msix(cn, NULL); |
600 |
|
601 |
for (idx = 0; idx < cn->vtpci_nvqs; idx++) |
602 |
vtpci_register_vq_msix(cn, idx, NULL); |
603 |
} |
604 |
|
605 |
vtpci_free_interrupts(cn); |
606 |
} |
607 |
|
Line 609
Link Here
|
609 |
vtpci_alloc_intr_resources(struct vtpci_common *cn) |
904 |
vtpci_alloc_intr_resources(struct vtpci_softc *sc) |
610 |
-- |
|
|
Line 614
Link Here
|
|
|
909 |
rid = 0; |
Lines 616-617
Link Here
|
616 |
if (cn->vtpci_flags & VTPCI_FLAG_INTX) { |
912 |
if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) |
617 |
rid = 0; |
|
|
618 |
-- |
Line 619
Link Here
|
619 |
} else |
914 |
else |
620 |
-- |
|
|
Lines 623-625
Link Here
|
623 |
* When using INTX or MSI interrupts, this resource handles all |
918 |
* For legacy and MSI interrupts, this single resource handles all |
624 |
* interrupts. When using MSIX, this resource handles just the |
919 |
* interrupts. For MSIX, this resource is used for the configuration |
625 |
* configuration changed interrupt. |
920 |
* changed interrupt. |
626 |
-- |
|
|
Lines 627-630
Link Here
|
627 |
intr = &cn->vtpci_device_interrupt; |
922 |
intr = &sc->vtpci_device_interrupt; |
628 |
|
923 |
error = vtpci_alloc_interrupt(sc, rid, flags, intr); |
629 |
error = vtpci_alloc_interrupt(cn, rid, flags, intr); |
924 |
if (error || sc->vtpci_flags & (VTPCI_FLAG_LEGACY | VTPCI_FLAG_MSI)) |
630 |
if (error || cn->vtpci_flags & (VTPCI_FLAG_INTX | VTPCI_FLAG_MSI)) |
|
|
631 |
-- |
Lines 633-638
Link Here
|
633 |
/* |
927 |
/* Subtract one for the configuration changed interrupt. */ |
634 |
* Now allocate the interrupts for the virtqueues. This may be one |
928 |
nvq_intrs = sc->vtpci_nmsix_resources - 1; |
635 |
* for all the virtqueues, or one for each virtqueue. Subtract one |
|
|
636 |
* below for because of the configuration changed interrupt. |
637 |
*/ |
638 |
nvq_intrs = cn->vtpci_nmsix_resources - 1; |
639 |
-- |
Line 640
Link Here
|
640 |
cn->vtpci_msix_vq_interrupts = malloc(nvq_intrs * |
930 |
intr = sc->vtpci_msix_vq_interrupts = malloc(nvq_intrs * |
641 |
-- |
|
|
Line 642
Link Here
|
642 |
if (cn->vtpci_msix_vq_interrupts == NULL) |
932 |
if (sc->vtpci_msix_vq_interrupts == NULL) |
643 |
-- |
|
|
Lines 645-646
Link Here
|
645 |
intr = cn->vtpci_msix_vq_interrupts; |
|
|
646 |
|
Line 648
Link Here
|
648 |
error = vtpci_alloc_interrupt(cn, rid, flags, intr); |
936 |
error = vtpci_alloc_interrupt(sc, rid, flags, intr); |
649 |
-- |
|
|
Line 657
Link Here
|
657 |
vtpci_setup_intx_interrupt(struct vtpci_common *cn, enum intr_type type) |
945 |
vtpci_setup_legacy_interrupt(struct vtpci_softc *sc, enum intr_type type) |
658 |
-- |
|
|
Line 662
Link Here
|
662 |
intr = &cn->vtpci_device_interrupt; |
950 |
intr = &sc->vtpci_device_interrupt; |
663 |
-- |
951 |
error = bus_setup_intr(sc->vtpci_dev, intr->vti_irq, type, NULL, |
|
|
952 |
vtpci_legacy_intr, sc, &intr->vti_handler); |
Lines 664-666
Link Here
|
664 |
error = bus_setup_intr(cn->vtpci_dev, intr->vti_irq, type, NULL, |
|
|
665 |
vtpci_intx_intr, cn, &intr->vti_handler); |
666 |
|
Line 671
Link Here
|
671 |
vtpci_setup_pervq_msix_interrupts(struct vtpci_common *cn, enum intr_type type) |
958 |
vtpci_setup_pervq_msix_interrupts(struct vtpci_softc *sc, enum intr_type type) |
672 |
-- |
|
|
Line 677
Link Here
|
677 |
intr = cn->vtpci_msix_vq_interrupts; |
964 |
intr = sc->vtpci_msix_vq_interrupts; |
678 |
-- |
|
|
Lines 679-680
Link Here
|
679 |
for (i = 0; i < cn->vtpci_nvqs; i++) { |
966 |
for (i = 0; i < sc->vtpci_nvqs; i++) { |
680 |
vqx = &cn->vtpci_vqs[i]; |
967 |
vqx = &sc->vtpci_vqs[i]; |
681 |
-- |
|
|
Line 685
Link Here
|
685 |
error = bus_setup_intr(cn->vtpci_dev, intr->vti_irq, type, |
972 |
error = bus_setup_intr(sc->vtpci_dev, intr->vti_irq, type, |
686 |
-- |
|
|
Line 698
Link Here
|
698 |
vtpci_set_host_msix_vectors(struct vtpci_common *cn) |
985 |
vtpci_setup_msix_interrupts(struct vtpci_softc *sc, enum intr_type type) |
699 |
-- |
|
|
Line 700
Link Here
|
|
|
987 |
device_t dev; |
988 |
struct vtpci_interrupt *intr; |
989 |
int error; |
990 |
|
991 |
dev = sc->vtpci_dev; |
992 |
intr = &sc->vtpci_device_interrupt; |
993 |
|
994 |
error = bus_setup_intr(dev, intr->vti_irq, type, NULL, |
995 |
vtpci_config_intr, sc, &intr->vti_handler); |
996 |
if (error) |
997 |
return (error); |
998 |
|
999 |
if (sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) { |
1000 |
intr = sc->vtpci_msix_vq_interrupts; |
1001 |
error = bus_setup_intr(dev, intr->vti_irq, type, |
1002 |
vtpci_vq_shared_intr_filter, vtpci_vq_shared_intr, sc, |
1003 |
&intr->vti_handler); |
1004 |
} else |
1005 |
error = vtpci_setup_pervq_msix_interrupts(sc, type); |
1006 |
|
1007 |
return (error ? error : vtpci_set_host_msix_vectors(sc)); |
1008 |
} |
1009 |
|
1010 |
static int |
1011 |
vtpci_setup_interrupts(struct vtpci_softc *sc, enum intr_type type) |
1012 |
{ |
1013 |
int error; |
1014 |
|
1015 |
type |= INTR_MPSAFE; |
1016 |
KASSERT(sc->vtpci_flags & VTPCI_FLAG_ITYPE_MASK, |
1017 |
("%s: no interrupt type selected %#x", __func__, sc->vtpci_flags)); |
1018 |
|
1019 |
error = vtpci_alloc_intr_resources(sc); |
1020 |
if (error) |
1021 |
return (error); |
1022 |
|
1023 |
if (sc->vtpci_flags & VTPCI_FLAG_LEGACY) |
1024 |
error = vtpci_setup_legacy_interrupt(sc, type); |
1025 |
else if (sc->vtpci_flags & VTPCI_FLAG_MSI) |
1026 |
error = vtpci_setup_msi_interrupt(sc, type); |
1027 |
else |
1028 |
error = vtpci_setup_msix_interrupts(sc, type); |
1029 |
|
1030 |
return (error); |
1031 |
} |
1032 |
|
1033 |
static int |
1034 |
vtpci_register_msix_vector(struct vtpci_softc *sc, int offset, |
1035 |
struct vtpci_interrupt *intr) |
1036 |
{ |
1037 |
device_t dev; |
1038 |
uint16_t vector; |
1039 |
|
1040 |
dev = sc->vtpci_dev; |
1041 |
|
1042 |
if (intr != NULL) { |
1043 |
/* Map from guest rid to host vector. */ |
1044 |
vector = intr->vti_rid - 1; |
1045 |
} else |
1046 |
vector = VIRTIO_MSI_NO_VECTOR; |
1047 |
|
1048 |
vtpci_write_config_2(sc, offset, vector); |
1049 |
|
1050 |
/* Read vector to determine if the host had sufficient resources. */ |
1051 |
if (vtpci_read_config_2(sc, offset) != vector) { |
1052 |
device_printf(dev, |
1053 |
"insufficient host resources for MSIX interrupts\n"); |
1054 |
return (ENODEV); |
1055 |
} |
1056 |
|
1057 |
return (0); |
1058 |
} |
1059 |
|
1060 |
static int |
1061 |
vtpci_set_host_msix_vectors(struct vtpci_softc *sc) |
1062 |
{ |
Line 701
Link Here
|
701 |
int idx, error; |
1064 |
int idx, offset, error; |
702 |
-- |
|
|
Lines 703-704
Link Here
|
703 |
intr = &cn->vtpci_device_interrupt; |
1066 |
intr = &sc->vtpci_device_interrupt; |
704 |
error = vtpci_register_cfg_msix(cn, intr); |
1067 |
offset = VIRTIO_MSI_CONFIG_VECTOR; |
705 |
-- |
1068 |
|
|
|
1069 |
error = vtpci_register_msix_vector(sc, offset, intr); |
Lines 708-710
Link Here
|
708 |
intr = cn->vtpci_msix_vq_interrupts; |
1073 |
intr = sc->vtpci_msix_vq_interrupts; |
709 |
for (idx = 0; idx < cn->vtpci_nvqs; idx++) { |
1074 |
offset = VIRTIO_MSI_QUEUE_VECTOR; |
710 |
if (cn->vtpci_vqs[idx].vtv_no_intr) |
1075 |
|
711 |
-- |
1076 |
for (idx = 0; idx < sc->vtpci_nvqs; idx++) { |
|
|
1077 |
vtpci_select_virtqueue(sc, idx); |
1078 |
|
1079 |
if (sc->vtpci_vqs[idx].vtv_no_intr) |
Line 715
Link Here
|
715 |
error = vtpci_register_vq_msix(cn, idx, tintr); |
1084 |
error = vtpci_register_msix_vector(sc, offset, tintr); |
716 |
-- |
|
|
Lines 723-724
Link Here
|
723 |
if (!cn->vtpci_vqs[idx].vtv_no_intr && |
1092 |
if (!sc->vtpci_vqs[idx].vtv_no_intr && |
724 |
(cn->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) == 0) |
1093 |
(sc->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) == 0) |
725 |
-- |
|
|
Line 732
Link Here
|
732 |
vtpci_setup_msix_interrupts(struct vtpci_common *cn, enum intr_type type) |
1101 |
vtpci_reinit_virtqueue(struct vtpci_softc *sc, int idx) |
733 |
-- |
|
|
Line 734
Link Here
|
734 |
struct vtpci_interrupt *intr; |
1103 |
struct vtpci_virtqueue *vqx; |
735 |
-- |
1104 |
struct virtqueue *vq; |
Line 736
Link Here
|
|
|
1106 |
uint16_t size; |
Line 737
Link Here
|
737 |
intr = &cn->vtpci_device_interrupt; |
1108 |
vqx = &sc->vtpci_vqs[idx]; |
738 |
-- |
1109 |
vq = vqx->vtv_vq; |
Lines 739-740
Link Here
|
739 |
error = bus_setup_intr(cn->vtpci_dev, intr->vti_irq, type, NULL, |
1111 |
KASSERT(vq != NULL, ("%s: vq %d not allocated", __func__, idx)); |
740 |
vtpci_config_intr, cn, &intr->vti_handler); |
1112 |
|
741 |
-- |
1113 |
vtpci_select_virtqueue(sc, idx); |
|
|
1114 |
size = vtpci_read_config_2(sc, VIRTIO_PCI_QUEUE_NUM); |
1115 |
|
1116 |
error = virtqueue_reinit(vq, size); |
Lines 744-745
Link Here
|
744 |
if (cn->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) { |
1120 |
vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, |
745 |
intr = &cn->vtpci_msix_vq_interrupts[0]; |
1121 |
virtqueue_paddr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); |
746 |
-- |
|
|
Lines 747-753
Link Here
|
747 |
error = bus_setup_intr(cn->vtpci_dev, intr->vti_irq, type, |
1123 |
return (0); |
748 |
vtpci_vq_shared_intr_filter, vtpci_vq_shared_intr, cn, |
|
|
749 |
&intr->vti_handler); |
750 |
} else |
751 |
error = vtpci_setup_pervq_msix_interrupts(cn, type); |
752 |
|
753 |
return (error ? error : vtpci_set_host_msix_vectors(cn)); |
754 |
-- |
Lines 756-757
Link Here
|
756 |
static int |
1126 |
static void |
757 |
vtpci_setup_intrs(struct vtpci_common *cn, enum intr_type type) |
1127 |
vtpci_free_interrupt(struct vtpci_softc *sc, struct vtpci_interrupt *intr) |
758 |
-- |
|
|
Line 759
Link Here
|
759 |
int error; |
1129 |
device_t dev; |
760 |
-- |
|
|
Lines 761-763
Link Here
|
761 |
type |= INTR_MPSAFE; |
1131 |
dev = sc->vtpci_dev; |
762 |
KASSERT(cn->vtpci_flags & VTPCI_FLAG_ITYPE_MASK, |
|
|
763 |
("%s: no interrupt type selected %#x", __func__, cn->vtpci_flags)); |
764 |
-- |
Lines 765-767
Link Here
|
765 |
error = vtpci_alloc_intr_resources(cn); |
1133 |
if (intr->vti_handler != NULL) { |
766 |
if (error) |
1134 |
bus_teardown_intr(dev, intr->vti_irq, intr->vti_handler); |
767 |
return (error); |
1135 |
intr->vti_handler = NULL; |
768 |
-- |
1136 |
} |
Lines 769-776
Link Here
|
769 |
if (cn->vtpci_flags & VTPCI_FLAG_INTX) |
1138 |
if (intr->vti_irq != NULL) { |
770 |
error = vtpci_setup_intx_interrupt(cn, type); |
1139 |
bus_release_resource(dev, SYS_RES_IRQ, intr->vti_rid, |
771 |
else if (cn->vtpci_flags & VTPCI_FLAG_MSI) |
1140 |
intr->vti_irq); |
772 |
error = vtpci_setup_msi_interrupt(cn, type); |
1141 |
intr->vti_irq = NULL; |
773 |
else |
1142 |
intr->vti_rid = -1; |
774 |
error = vtpci_setup_msix_interrupts(cn, type); |
1143 |
} |
775 |
|
|
|
776 |
return (error); |
777 |
-- |
Lines 779-780
Link Here
|
779 |
int |
1146 |
static void |
780 |
vtpci_setup_interrupts(struct vtpci_common *cn, enum intr_type type) |
1147 |
vtpci_free_interrupts(struct vtpci_softc *sc) |
781 |
-- |
|
|
Lines 782-783
Link Here
|
782 |
device_t dev; |
1149 |
struct vtpci_interrupt *intr; |
783 |
int attempt, error; |
1150 |
int i, nvq_intrs; |
784 |
-- |
|
|
Line 785
Link Here
|
785 |
dev = cn->vtpci_dev; |
1152 |
vtpci_free_interrupt(sc, &sc->vtpci_device_interrupt); |
786 |
-- |
|
|
Lines 787-809
Link Here
|
787 |
for (attempt = 0; attempt < 5; attempt++) { |
1154 |
if (sc->vtpci_nmsix_resources != 0) { |
788 |
/* |
1155 |
nvq_intrs = sc->vtpci_nmsix_resources - 1; |
789 |
* Start with the most desirable interrupt configuration and |
1156 |
sc->vtpci_nmsix_resources = 0; |
790 |
* fallback towards less desirable ones. |
|
|
791 |
*/ |
792 |
switch (attempt) { |
793 |
case 0: |
794 |
error = vtpci_alloc_intr_msix_pervq(cn); |
795 |
break; |
796 |
case 1: |
797 |
error = vtpci_alloc_intr_msix_shared(cn); |
798 |
break; |
799 |
case 2: |
800 |
error = vtpci_alloc_intr_msi(cn); |
801 |
break; |
802 |
case 3: |
803 |
error = vtpci_alloc_intr_intx(cn); |
804 |
break; |
805 |
default: |
806 |
device_printf(dev, |
807 |
"exhausted all interrupt allocation attempts\n"); |
808 |
return (ENXIO); |
809 |
} |
810 |
-- |
Lines 811-812
Link Here
|
811 |
if (error == 0 && vtpci_setup_intrs(cn, type) == 0) |
1158 |
intr = sc->vtpci_msix_vq_interrupts; |
812 |
break; |
1159 |
if (intr != NULL) { |
813 |
-- |
1160 |
for (i = 0; i < nvq_intrs; i++, intr++) |
|
|
1161 |
vtpci_free_interrupt(sc, intr); |
Line 814
Link Here
|
814 |
vtpci_cleanup_setup_intr_attempt(cn); |
1163 |
free(sc->vtpci_msix_vq_interrupts, M_DEVBUF); |
815 |
-- |
1164 |
sc->vtpci_msix_vq_interrupts = NULL; |
|
|
1165 |
} |
Lines 817-826
Link Here
|
817 |
if (bootverbose) { |
1168 |
if (sc->vtpci_flags & (VTPCI_FLAG_MSI | VTPCI_FLAG_MSIX)) |
818 |
if (cn->vtpci_flags & VTPCI_FLAG_INTX) |
1169 |
pci_release_msi(sc->vtpci_dev); |
819 |
device_printf(dev, "using legacy interrupt\n"); |
|
|
820 |
else if (cn->vtpci_flags & VTPCI_FLAG_MSI) |
821 |
device_printf(dev, "using MSI interrupt\n"); |
822 |
else if (cn->vtpci_flags & VTPCI_FLAG_SHARED_MSIX) |
823 |
device_printf(dev, "using shared MSIX interrupts\n"); |
824 |
else |
825 |
device_printf(dev, "using per VQ MSIX interrupts\n"); |
826 |
} |
827 |
-- |
Line 828
Link Here
|
828 |
return (0); |
1171 |
sc->vtpci_flags &= ~VTPCI_FLAG_ITYPE_MASK; |
829 |
-- |
|
|
Lines 831-832
Link Here
|
831 |
static int |
1174 |
static void |
832 |
vtpci_reinit_virtqueue(struct vtpci_common *cn, int idx) |
1175 |
vtpci_free_virtqueues(struct vtpci_softc *sc) |
833 |
-- |
|
|
Lines 835-836
Link Here
|
835 |
struct virtqueue *vq; |
1178 |
int idx; |
836 |
int error; |
|
|
837 |
-- |
Lines 838-839
Link Here
|
838 |
vqx = &cn->vtpci_vqs[idx]; |
1180 |
for (idx = 0; idx < sc->vtpci_nvqs; idx++) { |
839 |
vq = vqx->vtv_vq; |
1181 |
vqx = &sc->vtpci_vqs[idx]; |
840 |
-- |
|
|
Line 841
Link Here
|
841 |
KASSERT(vq != NULL, ("%s: vq %d not allocated", __func__, idx)); |
1183 |
vtpci_select_virtqueue(sc, idx); |
842 |
-- |
1184 |
vtpci_write_config_4(sc, VIRTIO_PCI_QUEUE_PFN, 0); |
Lines 843-845
Link Here
|
843 |
error = virtqueue_reinit(vq, vtpci_get_vq_size(cn, idx)); |
1186 |
virtqueue_free(vqx->vtv_vq); |
844 |
if (error == 0) |
1187 |
vqx->vtv_vq = NULL; |
845 |
vtpci_set_vq(cn, vq); |
1188 |
} |
846 |
-- |
|
|
Line 847
Link Here
|
847 |
return (error); |
1190 |
free(sc->vtpci_vqs, M_DEVBUF); |
848 |
-- |
1191 |
sc->vtpci_vqs = NULL; |
|
|
1192 |
sc->vtpci_nvqs = 0; |
Line 851
Link Here
|
851 |
vtpci_intx_intr(void *xcn) |
1196 |
vtpci_release_child_resources(struct vtpci_softc *sc) |
852 |
-- |
|
|
Line 853
Link Here
|
853 |
struct vtpci_common *cn; |
1198 |
|
854 |
-- |
1199 |
vtpci_free_interrupts(sc); |
|
|
1200 |
vtpci_free_virtqueues(sc); |
1201 |
} |
1202 |
|
1203 |
static void |
1204 |
vtpci_cleanup_setup_intr_attempt(struct vtpci_softc *sc) |
1205 |
{ |
1206 |
int idx; |
1207 |
|
1208 |
if (sc->vtpci_flags & VTPCI_FLAG_MSIX) { |
1209 |
vtpci_write_config_2(sc, VIRTIO_MSI_CONFIG_VECTOR, |
1210 |
VIRTIO_MSI_NO_VECTOR); |
1211 |
|
1212 |
for (idx = 0; idx < sc->vtpci_nvqs; idx++) { |
1213 |
vtpci_select_virtqueue(sc, idx); |
1214 |
vtpci_write_config_2(sc, VIRTIO_MSI_QUEUE_VECTOR, |
1215 |
VIRTIO_MSI_NO_VECTOR); |
1216 |
} |
1217 |
} |
1218 |
|
1219 |
vtpci_free_interrupts(sc); |
1220 |
} |
1221 |
|
1222 |
static void |
1223 |
vtpci_reset(struct vtpci_softc *sc) |
1224 |
{ |
1225 |
|
1226 |
/* |
1227 |
* Setting the status to RESET sets the host device to |
1228 |
* the original, uninitialized state. |
1229 |
*/ |
1230 |
vtpci_set_status(sc->vtpci_dev, VIRTIO_CONFIG_STATUS_RESET); |
1231 |
} |
1232 |
|
1233 |
static void |
1234 |
vtpci_select_virtqueue(struct vtpci_softc *sc, int idx) |
1235 |
{ |
1236 |
|
1237 |
vtpci_write_config_2(sc, VIRTIO_PCI_QUEUE_SEL, idx); |
1238 |
} |
1239 |
|
1240 |
static void |
1241 |
vtpci_legacy_intr(void *xsc) |
1242 |
{ |
1243 |
struct vtpci_softc *sc; |
Lines 858-859
Link Here
|
858 |
cn = xcn; |
1248 |
sc = xsc; |
859 |
isr = vtpci_read_isr(cn); |
1249 |
vqx = &sc->vtpci_vqs[0]; |
860 |
-- |
|
|
Line 861
Link Here
|
|
|
1251 |
/* Reading the ISR also clears it. */ |
1252 |
isr = vtpci_read_config_1(sc, VIRTIO_PCI_ISR); |
1253 |
|
Line 862
Link Here
|
862 |
vtpci_config_intr(cn); |
1255 |
vtpci_config_intr(sc); |
863 |
-- |
|
|
Lines 865-866
Link Here
|
865 |
vqx = &cn->vtpci_vqs[0]; |
1258 |
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) { |
866 |
for (i = 0; i < cn->vtpci_nvqs; i++, vqx++) { |
|
|
867 |
-- |
Line 874
Link Here
|
874 |
vtpci_vq_shared_intr_filter(void *xcn) |
1266 |
vtpci_vq_shared_intr_filter(void *xsc) |
875 |
-- |
|
|
Line 876
Link Here
|
876 |
struct vtpci_common *cn; |
1268 |
struct vtpci_softc *sc; |
877 |
-- |
|
|
Lines 880-881
Link Here
|
880 |
cn = xcn; |
|
|
881 |
vqx = &cn->vtpci_vqs[0]; |
Line 883
Link Here
|
|
|
1273 |
sc = xsc; |
1274 |
vqx = &sc->vtpci_vqs[0]; |
Line 884
Link Here
|
884 |
for (i = 0; i < cn->vtpci_nvqs; i++, vqx++) { |
1276 |
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) { |
885 |
-- |
|
|
Line 893
Link Here
|
893 |
vtpci_vq_shared_intr(void *xcn) |
1285 |
vtpci_vq_shared_intr(void *xsc) |
894 |
-- |
|
|
Line 895
Link Here
|
895 |
struct vtpci_common *cn; |
1287 |
struct vtpci_softc *sc; |
896 |
-- |
|
|
Lines 899-900
Link Here
|
899 |
cn = xcn; |
1291 |
sc = xsc; |
900 |
vqx = &cn->vtpci_vqs[0]; |
1292 |
vqx = &sc->vtpci_vqs[0]; |
901 |
-- |
|
|
Line 902
Link Here
|
902 |
for (i = 0; i < cn->vtpci_nvqs; i++, vqx++) { |
1294 |
for (i = 0; i < sc->vtpci_nvqs; i++, vqx++) { |
903 |
-- |
|
|
Line 930
Link Here
|
930 |
vtpci_config_intr(void *xcn) |
1322 |
vtpci_config_intr(void *xsc) |
931 |
-- |
|
|
Line 932
Link Here
|
932 |
struct vtpci_common *cn; |
1324 |
struct vtpci_softc *sc; |
933 |
-- |
|
|
Lines 935-936
Link Here
|
935 |
cn = xcn; |
1327 |
sc = xsc; |
936 |
child = cn->vtpci_child_dev; |
1328 |
child = sc->vtpci_child_dev; |
937 |
-- |
|
|
Lines 940-1000
Link Here
|
940 |
} |
|
|
941 |
|
942 |
static int |
943 |
vtpci_feature_sysctl(struct sysctl_req *req, struct vtpci_common *cn, |
944 |
uint64_t features) |
945 |
{ |
946 |
struct sbuf *sb; |
947 |
int error; |
948 |
|
949 |
sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); |
950 |
if (sb == NULL) |
951 |
return (ENOMEM); |
952 |
|
953 |
error = virtio_describe_sbuf(sb, features, cn->vtpci_child_feat_desc); |
954 |
sbuf_delete(sb); |
955 |
|
956 |
return (error); |
957 |
} |
958 |
|
959 |
static int |
960 |
vtpci_host_features_sysctl(SYSCTL_HANDLER_ARGS) |
961 |
{ |
962 |
struct vtpci_common *cn; |
963 |
|
964 |
cn = arg1; |
965 |
|
966 |
return (vtpci_feature_sysctl(req, cn, cn->vtpci_host_features)); |
967 |
} |
968 |
|
969 |
static int |
970 |
vtpci_negotiated_features_sysctl(SYSCTL_HANDLER_ARGS) |
971 |
{ |
972 |
struct vtpci_common *cn; |
973 |
|
974 |
cn = arg1; |
975 |
|
976 |
return (vtpci_feature_sysctl(req, cn, cn->vtpci_features)); |
977 |
} |
978 |
|
979 |
static void |
980 |
vtpci_setup_sysctl(struct vtpci_common *cn) |
981 |
{ |
982 |
device_t dev; |
983 |
struct sysctl_ctx_list *ctx; |
984 |
struct sysctl_oid *tree; |
985 |
struct sysctl_oid_list *child; |
986 |
|
987 |
dev = cn->vtpci_dev; |
988 |
ctx = device_get_sysctl_ctx(dev); |
989 |
tree = device_get_sysctl_tree(dev); |
990 |
child = SYSCTL_CHILDREN(tree); |
991 |
|
992 |
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "nvqs", |
993 |
CTLFLAG_RD, &cn->vtpci_nvqs, 0, "Number of virtqueues"); |
994 |
|
995 |
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "host_features", |
996 |
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, cn, 0, |
997 |
vtpci_host_features_sysctl, "A", "Features supported by the host"); |
998 |
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "negotiated_features", |
999 |
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, cn, 0, |
1000 |
vtpci_negotiated_features_sysctl, "A", "Features negotiated"); |