Blame view
drivers/virtio/virtio_pci_common.c
15.2 KB
3343660d8 virtio: PCI device |
1 |
/* |
a90fdce9d virtio_pci: updat... |
2 |
* Virtio PCI driver - common functionality for all device versions |
3343660d8 virtio: PCI device |
3 4 5 6 7 |
* * This module allows virtio devices to be used over a virtual PCI device. * This can be used with QEMU based VMMs like KVM or Xen. * * Copyright IBM Corp. 2007 |
a90fdce9d virtio_pci: updat... |
8 |
* Copyright Red Hat, Inc. 2014 |
3343660d8 virtio: PCI device |
9 10 11 |
* * Authors: * Anthony Liguori <aliguori@us.ibm.com> |
a90fdce9d virtio_pci: updat... |
12 13 |
* Rusty Russell <rusty@rustcorp.com.au> * Michael S. Tsirkin <mst@redhat.com> |
3343660d8 virtio: PCI device |
14 15 16 17 18 |
* * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. * */ |
5f4c97608 virtio_pci: renam... |
19 |
#include "virtio_pci_common.h" |
3343660d8 virtio: PCI device |
20 |
|
ac399d8f3 virtio_pci: add m... |
21 22 23 24 25 26 27 |
static bool force_legacy = false; #if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY) module_param(force_legacy, bool, 0444); MODULE_PARM_DESC(force_legacy, "Force legacy mode for transitional virtio 1 devices"); #endif |
e6af578c5 virtio-pci: make ... |
28 |
/* wait for pending irq handlers */ |
38eb4a29a virtio_pci: split... |
29 |
void vp_synchronize_vectors(struct virtio_device *vdev) |
e6af578c5 virtio-pci: make ... |
30 31 32 |
{ struct virtio_pci_device *vp_dev = to_vp_device(vdev); int i; |
0b0f9dc52 Revert "virtio_pc... |
33 34 35 36 |
if (vp_dev->intx_enabled) synchronize_irq(vp_dev->pci_dev->irq); for (i = 0; i < vp_dev->msix_vectors; ++i) |
fa3a32793 virtio_pci: use p... |
37 |
synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); |
e6af578c5 virtio-pci: make ... |
38 |
} |
3343660d8 virtio: PCI device |
39 |
/* the notify function used when creating a virt queue */ |
38eb4a29a virtio_pci: split... |
40 |
bool vp_notify(struct virtqueue *vq) |
3343660d8 virtio: PCI device |
41 |
{ |
3343660d8 virtio: PCI device |
42 43 |
/* we write the queue's selector into the notification register to * signal the other end */ |
f30eaf4a0 virtio_pci: use p... |
44 |
iowrite16(vq->index, (void __iomem *)vq->priv); |
46f9c2b92 virtio_ring: chan... |
45 |
return true; |
3343660d8 virtio: PCI device |
46 |
} |
77cf52465 virtio_pci: split... |
47 48 49 50 |
/* Handle a configuration change: Tell driver if it wants to know. */ static irqreturn_t vp_config_changed(int irq, void *opaque) { struct virtio_pci_device *vp_dev = opaque; |
77cf52465 virtio_pci: split... |
51 |
|
016c98c6f virtio: unify con... |
52 |
virtio_config_changed(&vp_dev->vdev); |
77cf52465 virtio_pci: split... |
53 54 55 56 57 58 59 |
return IRQ_HANDLED; } /* Notify all virtqueues on an interrupt. */ static irqreturn_t vp_vring_interrupt(int irq, void *opaque) { struct virtio_pci_device *vp_dev = opaque; |
0a9b3f47d Revert "virtio_pc... |
60 |
struct virtio_pci_vq_info *info; |
77cf52465 virtio_pci: split... |
61 |
irqreturn_t ret = IRQ_NONE; |
0a9b3f47d Revert "virtio_pc... |
62 |
unsigned long flags; |
77cf52465 virtio_pci: split... |
63 |
|
0a9b3f47d Revert "virtio_pc... |
64 65 66 |
spin_lock_irqsave(&vp_dev->lock, flags); list_for_each_entry(info, &vp_dev->virtqueues, node) { if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) |
77cf52465 virtio_pci: split... |
67 68 |
ret = IRQ_HANDLED; } |
0a9b3f47d Revert "virtio_pc... |
69 |
spin_unlock_irqrestore(&vp_dev->lock, flags); |
77cf52465 virtio_pci: split... |
70 71 72 |
return ret; } |
3343660d8 virtio: PCI device |
73 74 75 76 77 78 79 80 81 |
/* A small wrapper to also acknowledge the interrupt when it's handled. * I really need an EIO hook for the vring so I can ack the interrupt once we * know that we'll be handling the IRQ but before we invoke the callback since * the callback may notify the host which results in the host attempting to * raise an interrupt that we would then mask once we acknowledged the * interrupt. */ static irqreturn_t vp_interrupt(int irq, void *opaque) { struct virtio_pci_device *vp_dev = opaque; |
3343660d8 virtio: PCI device |
82 83 84 85 |
u8 isr; /* reading the ISR has the effect of also clearing it so it's very * important to save off the value. */ |
af535722f virtio_pci: add i... |
86 |
isr = ioread8(vp_dev->isr); |
3343660d8 virtio: PCI device |
87 88 89 90 91 92 |
/* It's definitely not us if the ISR was not high */ if (!isr) return IRQ_NONE; /* Configuration change? Tell driver if it wants to know. */ |
77cf52465 virtio_pci: split... |
93 94 |
if (isr & VIRTIO_PCI_ISR_CONFIG) vp_config_changed(irq, opaque); |
3343660d8 virtio: PCI device |
95 |
|
77cf52465 virtio_pci: split... |
96 |
return vp_vring_interrupt(irq, opaque); |
3343660d8 virtio: PCI device |
97 |
} |
0b0f9dc52 Revert "virtio_pc... |
98 99 100 101 102 |
static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, bool per_vq_vectors, struct irq_affinity *desc) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); const char *name = dev_name(&vp_dev->vdev.dev); |
ba74b6f7f virtio_pci: fix c... |
103 |
unsigned flags = PCI_IRQ_MSIX; |
0b0f9dc52 Revert "virtio_pc... |
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
unsigned i, v; int err = -ENOMEM; vp_dev->msix_vectors = nvectors; vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names, GFP_KERNEL); if (!vp_dev->msix_names) goto error; vp_dev->msix_affinity_masks = kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks, GFP_KERNEL); if (!vp_dev->msix_affinity_masks) goto error; for (i = 0; i < nvectors; ++i) if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i], GFP_KERNEL)) goto error; |
ba74b6f7f virtio_pci: fix c... |
122 123 124 125 |
if (desc) { flags |= PCI_IRQ_AFFINITY; desc->pre_vectors++; /* virtio config vector */ } |
0b0f9dc52 Revert "virtio_pc... |
126 |
err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors, |
ba74b6f7f virtio_pci: fix c... |
127 |
nvectors, flags, desc); |
0b0f9dc52 Revert "virtio_pc... |
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
if (err < 0) goto error; vp_dev->msix_enabled = 1; /* Set the vector used for configuration */ v = vp_dev->msix_used_vectors; snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-config", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), vp_config_changed, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; ++vp_dev->msix_used_vectors; v = vp_dev->config_vector(vp_dev, v); /* Verify we had enough resources to assign the vector */ if (v == VIRTIO_MSI_NO_VECTOR) { err = -EBUSY; goto error; } if (!per_vq_vectors) { /* Shared vector for all VQs */ v = vp_dev->msix_used_vectors; snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-virtqueues", name); err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), vp_vring_interrupt, 0, vp_dev->msix_names[v], vp_dev); if (err) goto error; ++vp_dev->msix_used_vectors; } return 0; error: return err; } |
0a9b3f47d Revert "virtio_pc... |
166 167 168 |
static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, void (*callback)(struct virtqueue *vq), const char *name, |
f94682dde virtio: add conte... |
169 |
bool ctx, |
0a9b3f47d Revert "virtio_pc... |
170 171 172 173 174 175 176 177 178 179 |
u16 msix_vec) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL); struct virtqueue *vq; unsigned long flags; /* fill out our structure that represents an active queue */ if (!info) return ERR_PTR(-ENOMEM); |
f94682dde virtio: add conte... |
180 |
vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx, |
0a9b3f47d Revert "virtio_pc... |
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
msix_vec); if (IS_ERR(vq)) goto out_info; info->vq = vq; if (callback) { spin_lock_irqsave(&vp_dev->lock, flags); list_add(&info->node, &vp_dev->virtqueues); spin_unlock_irqrestore(&vp_dev->lock, flags); } else { INIT_LIST_HEAD(&info->node); } vp_dev->vqs[index] = info; return vq; out_info: kfree(info); return vq; } static void vp_del_vq(struct virtqueue *vq) { struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index]; unsigned long flags; spin_lock_irqsave(&vp_dev->lock, flags); list_del(&info->node); spin_unlock_irqrestore(&vp_dev->lock, flags); vp_dev->del_vq(info); kfree(info); } |
0b0f9dc52 Revert "virtio_pc... |
215 216 |
/* the config->del_vqs() implementation */ void vp_del_vqs(struct virtio_device *vdev) |
d2a7ddda9 virtio: find_vqs/... |
217 |
{ |
e969fed54 virtio: refactor ... |
218 |
struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
d2a7ddda9 virtio: find_vqs/... |
219 |
struct virtqueue *vq, *n; |
0b0f9dc52 Revert "virtio_pc... |
220 |
int i; |
d2a7ddda9 virtio: find_vqs/... |
221 |
|
e969fed54 virtio: refactor ... |
222 |
list_for_each_entry_safe(vq, n, &vdev->vqs, list) { |
0a9b3f47d Revert "virtio_pc... |
223 224 |
if (vp_dev->per_vq_vectors) { int v = vp_dev->vqs[vq->index]->msix_vector; |
fa3a32793 virtio_pci: use p... |
225 |
|
2f8dc3a01 virtio-pci: Remov... |
226 227 228 229 230 231 |
if (v != VIRTIO_MSI_NO_VECTOR) { int irq = pci_irq_vector(vp_dev->pci_dev, v); irq_set_affinity_hint(irq, NULL); free_irq(irq, vq); } |
fa3a32793 virtio_pci: use p... |
232 |
} |
0a9b3f47d Revert "virtio_pc... |
233 |
vp_del_vq(vq); |
e969fed54 virtio: refactor ... |
234 |
} |
0a9b3f47d Revert "virtio_pc... |
235 |
vp_dev->per_vq_vectors = false; |
82af8ce84 virtio_pci: optio... |
236 |
|
0b0f9dc52 Revert "virtio_pc... |
237 238 239 240 |
if (vp_dev->intx_enabled) { free_irq(vp_dev->pci_dev->irq, vp_dev); vp_dev->intx_enabled = 0; } |
66f2f5554 virtio_pci: merge... |
241 |
|
0b0f9dc52 Revert "virtio_pc... |
242 243 |
for (i = 0; i < vp_dev->msix_used_vectors; ++i) free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev); |
66f2f5554 virtio_pci: merge... |
244 |
|
0b0f9dc52 Revert "virtio_pc... |
245 246 |
for (i = 0; i < vp_dev->msix_vectors; i++) if (vp_dev->msix_affinity_masks[i]) |
07ec51480 virtio_pci: use s... |
247 |
free_cpumask_var(vp_dev->msix_affinity_masks[i]); |
0b0f9dc52 Revert "virtio_pc... |
248 |
if (vp_dev->msix_enabled) { |
66f2f5554 virtio_pci: merge... |
249 250 |
/* Disable the vector used for configuration */ vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR); |
0b0f9dc52 Revert "virtio_pc... |
251 252 |
pci_free_irq_vectors(vp_dev->pci_dev); vp_dev->msix_enabled = 0; |
66f2f5554 virtio_pci: merge... |
253 |
} |
0b0f9dc52 Revert "virtio_pc... |
254 255 256 257 258 259 |
vp_dev->msix_vectors = 0; vp_dev->msix_used_vectors = 0; kfree(vp_dev->msix_names); vp_dev->msix_names = NULL; kfree(vp_dev->msix_affinity_masks); vp_dev->msix_affinity_masks = NULL; |
0a9b3f47d Revert "virtio_pc... |
260 261 |
kfree(vp_dev->vqs); vp_dev->vqs = NULL; |
d2a7ddda9 virtio: find_vqs/... |
262 |
} |
a3cbec697 virtio_pci: split... |
263 |
static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, |
52a615161 virtio_pci: simpl... |
264 |
struct virtqueue *vqs[], vq_callback_t *callbacks[], |
bf951b104 Revert "virtio_pc... |
265 |
const char * const names[], bool per_vq_vectors, |
f94682dde virtio: add conte... |
266 |
const bool *ctx, |
bf951b104 Revert "virtio_pc... |
267 |
struct irq_affinity *desc) |
d2a7ddda9 virtio: find_vqs/... |
268 |
{ |
e969fed54 virtio: refactor ... |
269 |
struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
f68d24082 virtio_pci: minor... |
270 |
u16 msix_vec; |
0b0f9dc52 Revert "virtio_pc... |
271 |
int i, err, nvectors, allocated_vectors; |
82af8ce84 virtio_pci: optio... |
272 |
|
0a9b3f47d Revert "virtio_pc... |
273 274 275 |
vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); if (!vp_dev->vqs) return -ENOMEM; |
bf951b104 Revert "virtio_pc... |
276 |
if (per_vq_vectors) { |
0b0f9dc52 Revert "virtio_pc... |
277 278 279 280 281 |
/* Best option: one for change interrupt, one per vq. */ nvectors = 1; for (i = 0; i < nvqs; ++i) if (callbacks[i]) ++nvectors; |
bf951b104 Revert "virtio_pc... |
282 |
} else { |
0b0f9dc52 Revert "virtio_pc... |
283 284 |
/* Second best: one for change, shared for all vqs. */ nvectors = 2; |
07ec51480 virtio_pci: use s... |
285 |
} |
0b0f9dc52 Revert "virtio_pc... |
286 287 |
err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors, per_vq_vectors ? desc : NULL); |
a3cbec697 virtio_pci: split... |
288 |
if (err) |
0b0f9dc52 Revert "virtio_pc... |
289 |
goto error_find; |
a3cbec697 virtio_pci: split... |
290 |
|
0a9b3f47d Revert "virtio_pc... |
291 |
vp_dev->per_vq_vectors = per_vq_vectors; |
0b0f9dc52 Revert "virtio_pc... |
292 |
allocated_vectors = vp_dev->msix_used_vectors; |
d2a7ddda9 virtio: find_vqs/... |
293 |
for (i = 0; i < nvqs; ++i) { |
6457f126c virtio: support r... |
294 295 296 |
if (!names[i]) { vqs[i] = NULL; continue; |
a3cbec697 virtio_pci: split... |
297 |
} |
0b0f9dc52 Revert "virtio_pc... |
298 |
if (!callbacks[i]) |
07ec51480 virtio_pci: use s... |
299 |
msix_vec = VIRTIO_MSI_NO_VECTOR; |
0a9b3f47d Revert "virtio_pc... |
300 |
else if (vp_dev->per_vq_vectors) |
0b0f9dc52 Revert "virtio_pc... |
301 302 303 |
msix_vec = allocated_vectors++; else msix_vec = VP_MSIX_VQ_VECTOR; |
0a9b3f47d Revert "virtio_pc... |
304 |
vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], |
f94682dde virtio: add conte... |
305 |
ctx ? ctx[i] : false, |
0a9b3f47d Revert "virtio_pc... |
306 |
msix_vec); |
e969fed54 virtio: refactor ... |
307 308 |
if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); |
0b0f9dc52 Revert "virtio_pc... |
309 |
goto error_find; |
e969fed54 virtio: refactor ... |
310 |
} |
0b22bd0ba virtio-pci: fix p... |
311 |
|
0a9b3f47d Revert "virtio_pc... |
312 |
if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR) |
5c34d002d virtio_pci: remov... |
313 |
continue; |
5c34d002d virtio_pci: remov... |
314 |
|
0b0f9dc52 Revert "virtio_pc... |
315 316 317 318 |
/* allocate per-vq irq if available and necessary */ snprintf(vp_dev->msix_names[msix_vec], sizeof *vp_dev->msix_names, "%s-%s", |
0b22bd0ba virtio-pci: fix p... |
319 |
dev_name(&vp_dev->vdev.dev), names[i]); |
fa3a32793 virtio_pci: use p... |
320 |
err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), |
0b0f9dc52 Revert "virtio_pc... |
321 322 323 |
vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); |
0a9b3f47d Revert "virtio_pc... |
324 |
if (err) |
0b0f9dc52 Revert "virtio_pc... |
325 |
goto error_find; |
d2a7ddda9 virtio: find_vqs/... |
326 327 |
} return 0; |
0b0f9dc52 Revert "virtio_pc... |
328 329 |
error_find: vp_del_vqs(vdev); |
e969fed54 virtio: refactor ... |
330 331 |
return err; } |
a3cbec697 virtio_pci: split... |
332 333 |
static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], |
f94682dde virtio: add conte... |
334 |
const char * const names[], const bool *ctx) |
a3cbec697 virtio_pci: split... |
335 336 337 |
{ struct virtio_pci_device *vp_dev = to_vp_device(vdev); int i, err; |
0a9b3f47d Revert "virtio_pc... |
338 339 340 |
vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); if (!vp_dev->vqs) return -ENOMEM; |
a3cbec697 virtio_pci: split... |
341 342 343 |
err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED, dev_name(&vdev->dev), vp_dev); if (err) |
0b0f9dc52 Revert "virtio_pc... |
344 |
goto out_del_vqs; |
a3cbec697 virtio_pci: split... |
345 |
|
0b0f9dc52 Revert "virtio_pc... |
346 |
vp_dev->intx_enabled = 1; |
0a9b3f47d Revert "virtio_pc... |
347 |
vp_dev->per_vq_vectors = false; |
a3cbec697 virtio_pci: split... |
348 349 350 351 352 |
for (i = 0; i < nvqs; ++i) { if (!names[i]) { vqs[i] = NULL; continue; } |
0a9b3f47d Revert "virtio_pc... |
353 |
vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], |
f94682dde virtio: add conte... |
354 |
ctx ? ctx[i] : false, |
0a9b3f47d Revert "virtio_pc... |
355 |
VIRTIO_MSI_NO_VECTOR); |
a3cbec697 virtio_pci: split... |
356 357 |
if (IS_ERR(vqs[i])) { err = PTR_ERR(vqs[i]); |
0b0f9dc52 Revert "virtio_pc... |
358 |
goto out_del_vqs; |
a3cbec697 virtio_pci: split... |
359 360 361 362 |
} } return 0; |
0b0f9dc52 Revert "virtio_pc... |
363 364 |
out_del_vqs: vp_del_vqs(vdev); |
a3cbec697 virtio_pci: split... |
365 366 |
return err; } |
e969fed54 virtio: refactor ... |
367 |
/* the config->find_vqs() implementation */ |
38eb4a29a virtio_pci: split... |
368 |
int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, |
fb5e31d97 virtio: allow dri... |
369 |
struct virtqueue *vqs[], vq_callback_t *callbacks[], |
f94682dde virtio: add conte... |
370 371 |
const char * const names[], const bool *ctx, struct irq_affinity *desc) |
e969fed54 virtio: refactor ... |
372 |
{ |
f68d24082 virtio_pci: minor... |
373 |
int err; |
e969fed54 virtio: refactor ... |
374 |
|
bf951b104 Revert "virtio_pc... |
375 |
/* Try MSI-X with one vector per queue. */ |
f94682dde virtio: add conte... |
376 |
err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc); |
bf951b104 Revert "virtio_pc... |
377 378 379 |
if (!err) return 0; /* Fallback: MSI-X with one vector for config, one shared for queues. */ |
f94682dde virtio: add conte... |
380 |
err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc); |
e969fed54 virtio: refactor ... |
381 382 |
if (!err) return 0; |
bf951b104 Revert "virtio_pc... |
383 |
/* Finally fall back to regular interrupts. */ |
f94682dde virtio: add conte... |
384 |
return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx); |
d2a7ddda9 virtio: find_vqs/... |
385 |
} |
38eb4a29a virtio_pci: split... |
386 |
const char *vp_bus_name(struct virtio_device *vdev) |
66846048f enable virtio_net... |
387 388 389 390 391 |
{ struct virtio_pci_device *vp_dev = to_vp_device(vdev); return pci_name(vp_dev->pci_dev); } |
75a0a52be virtio: introduce... |
392 393 394 395 396 |
/* Setup the affinity for a virtqueue: * - force the affinity for per vq vector * - OR over all affinities for shared MSI * - ignore the affinity request if we're using INTX */ |
38eb4a29a virtio_pci: split... |
397 |
int vp_set_vq_affinity(struct virtqueue *vq, int cpu) |
75a0a52be virtio: introduce... |
398 399 400 |
{ struct virtio_device *vdev = vq->vdev; struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
0a9b3f47d Revert "virtio_pc... |
401 402 403 |
struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index]; struct cpumask *mask; unsigned int irq; |
75a0a52be virtio: introduce... |
404 405 406 |
if (!vq->callback) return -EINVAL; |
2008c1544 Revert "virtio_pc... |
407 |
if (vp_dev->msix_enabled) { |
0a9b3f47d Revert "virtio_pc... |
408 409 |
mask = vp_dev->msix_affinity_masks[info->msix_vector]; irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector); |
75a0a52be virtio: introduce... |
410 411 412 |
if (cpu == -1) irq_set_affinity_hint(irq, NULL); else { |
210d150e1 virtio_pci: Clear... |
413 |
cpumask_clear(mask); |
75a0a52be virtio: introduce... |
414 415 416 417 418 419 |
cpumask_set_cpu(cpu, mask); irq_set_affinity_hint(irq, mask); } } return 0; } |
bbaba4795 virtio: provide a... |
420 421 422 |
const struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); |
bbaba4795 virtio: provide a... |
423 |
|
0a9b3f47d Revert "virtio_pc... |
424 425 |
if (!vp_dev->per_vq_vectors || vp_dev->vqs[index]->msix_vector == VIRTIO_MSI_NO_VECTOR) |
bbaba4795 virtio: provide a... |
426 |
return NULL; |
0a9b3f47d Revert "virtio_pc... |
427 428 |
return pci_irq_get_affinity(vp_dev->pci_dev, vp_dev->vqs[index]->msix_vector); |
bbaba4795 virtio: provide a... |
429 |
} |
9e266ece2 virtio_pci: pm: U... |
430 |
#ifdef CONFIG_PM_SLEEP |
f0fe6f115 virtio: pci: add ... |
431 432 433 434 |
static int virtio_pci_freeze(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); |
f0fe6f115 virtio: pci: add ... |
435 |
int ret; |
c6716bae5 virtio-pci: move ... |
436 |
ret = virtio_device_freeze(&vp_dev->vdev); |
f0fe6f115 virtio: pci: add ... |
437 438 439 440 441 |
if (!ret) pci_disable_device(pci_dev); return ret; } |
0517fdd15 virtio-pci: drop ... |
442 |
static int virtio_pci_restore(struct device *dev) |
f0fe6f115 virtio: pci: add ... |
443 444 445 446 447 448 449 450 |
{ struct pci_dev *pci_dev = to_pci_dev(dev); struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); int ret; ret = pci_enable_device(pci_dev); if (ret) return ret; |
0517fdd15 virtio-pci: drop ... |
451 |
|
f0fe6f115 virtio: pci: add ... |
452 |
pci_set_master(pci_dev); |
c6716bae5 virtio-pci: move ... |
453 |
return virtio_device_restore(&vp_dev->vdev); |
f0fe6f115 virtio: pci: add ... |
454 |
} |
9a4253db0 virtio_pci: move ... |
455 |
static const struct dev_pm_ops virtio_pci_pm_ops = { |
f878d0be2 virtio-pci: switc... |
456 |
SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore) |
d07753638 virtio: pci: swit... |
457 |
}; |
3343660d8 virtio: PCI device |
458 |
#endif |
9a4253db0 virtio_pci: move ... |
459 460 461 462 |
/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */ static const struct pci_device_id virtio_pci_id_table[] = { |
caf02abf9 PCI: Add QEMU top... |
463 |
{ PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) }, |
9a4253db0 virtio_pci: move ... |
464 465 466 467 |
{ 0 } }; MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); |
ff31d2e28 virtio_pci: move ... |
468 469 470 471 472 473 474 475 476 477 |
static void virtio_pci_release_dev(struct device *_d) { struct virtio_device *vdev = dev_to_virtio(_d); struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* As struct device is a kobject, it's not safe to * free the memory (including the reference counter itself) * until it's release callback. */ kfree(vp_dev); } |
9a4253db0 virtio_pci: move ... |
478 479 480 |
static int virtio_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { |
ff31d2e28 virtio_pci: move ... |
481 482 483 484 485 486 487 488 489 490 491 492 |
struct virtio_pci_device *vp_dev; int rc; /* allocate our structure and fill it out */ vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL); if (!vp_dev) return -ENOMEM; pci_set_drvdata(pci_dev, vp_dev); vp_dev->vdev.dev.parent = &pci_dev->dev; vp_dev->vdev.dev.release = virtio_pci_release_dev; vp_dev->pci_dev = pci_dev; |
0a9b3f47d Revert "virtio_pc... |
493 494 |
INIT_LIST_HEAD(&vp_dev->virtqueues); spin_lock_init(&vp_dev->lock); |
ff31d2e28 virtio_pci: move ... |
495 |
|
ff31d2e28 virtio_pci: move ... |
496 497 498 499 |
/* enable the device */ rc = pci_enable_device(pci_dev); if (rc) goto err_enable_device; |
ac399d8f3 virtio_pci: add m... |
500 |
if (force_legacy) { |
1fcf0512c virtio_pci: moder... |
501 |
rc = virtio_pci_legacy_probe(vp_dev); |
ac399d8f3 virtio_pci: add m... |
502 503 504 505 506 507 508 509 510 511 512 513 |
/* Also try modern mode if we can't map BAR0 (no IO space). */ if (rc == -ENODEV || rc == -ENOMEM) rc = virtio_pci_modern_probe(vp_dev); if (rc) goto err_probe; } else { rc = virtio_pci_modern_probe(vp_dev); if (rc == -ENODEV) rc = virtio_pci_legacy_probe(vp_dev); if (rc) goto err_probe; } |
ff31d2e28 virtio_pci: move ... |
514 515 516 517 518 519 520 521 522 523 |
pci_set_master(pci_dev); rc = register_virtio_device(&vp_dev->vdev); if (rc) goto err_register; return 0; err_register: |
1fcf0512c virtio_pci: moder... |
524 525 526 527 |
if (vp_dev->ioaddr) virtio_pci_legacy_remove(vp_dev); else virtio_pci_modern_remove(vp_dev); |
ff31d2e28 virtio_pci: move ... |
528 |
err_probe: |
ff31d2e28 virtio_pci: move ... |
529 530 531 532 |
pci_disable_device(pci_dev); err_enable_device: kfree(vp_dev); return rc; |
9a4253db0 virtio_pci: move ... |
533 534 535 536 |
} static void virtio_pci_remove(struct pci_dev *pci_dev) { |
ff31d2e28 virtio_pci: move ... |
537 |
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); |
2989be09a virtio_pci: fix u... |
538 |
struct device *dev = get_device(&vp_dev->vdev.dev); |
ff31d2e28 virtio_pci: move ... |
539 540 |
unregister_virtio_device(&vp_dev->vdev); |
1fcf0512c virtio_pci: moder... |
541 542 543 544 |
if (vp_dev->ioaddr) virtio_pci_legacy_remove(vp_dev); else virtio_pci_modern_remove(vp_dev); |
ff31d2e28 virtio_pci: move ... |
545 |
|
ff31d2e28 virtio_pci: move ... |
546 |
pci_disable_device(pci_dev); |
2989be09a virtio_pci: fix u... |
547 |
put_device(dev); |
9a4253db0 virtio_pci: move ... |
548 549 550 551 552 553 554 555 556 557 558 559 560 |
} static struct pci_driver virtio_pci_driver = { .name = "virtio-pci", .id_table = virtio_pci_id_table, .probe = virtio_pci_probe, .remove = virtio_pci_remove, #ifdef CONFIG_PM_SLEEP .driver.pm = &virtio_pci_pm_ops, #endif }; module_pci_driver(virtio_pci_driver); |
5ff16110c virtio_pci: resto... |
561 562 563 564 565 |
MODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>"); MODULE_DESCRIPTION("virtio-pci"); MODULE_LICENSE("GPL"); MODULE_VERSION("1"); |