Blame view

virt/kvm/assigned-dev.c 20.9 KB
bfd99ff5d   Avi Kivity   KVM: Move assigne...
1
2
3
  /*
   * Kernel-based Virtual Machine - device assignment support
   *
221d059d1   Avi Kivity   KVM: Update Red H...
4
   * Copyright (C) 2010 Red Hat, Inc. and/or its affiliates.
bfd99ff5d   Avi Kivity   KVM: Move assigne...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
   *
   * This work is licensed under the terms of the GNU GPL, version 2.  See
   * the COPYING file in the top-level directory.
   *
   */
  
  #include <linux/kvm_host.h>
  #include <linux/kvm.h>
  #include <linux/uaccess.h>
  #include <linux/vmalloc.h>
  #include <linux/errno.h>
  #include <linux/spinlock.h>
  #include <linux/pci.h>
  #include <linux/interrupt.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
3d27e23b1   Alex Williamson   KVM: Device assig...
20
21
  #include <linux/namei.h>
  #include <linux/fs.h>
bfd99ff5d   Avi Kivity   KVM: Move assigne...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  #include "irq.h"
  
  static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
  						      int assigned_dev_id)
  {
  	struct list_head *ptr;
  	struct kvm_assigned_dev_kernel *match;
  
  	list_for_each(ptr, head) {
  		match = list_entry(ptr, struct kvm_assigned_dev_kernel, list);
  		if (match->assigned_dev_id == assigned_dev_id)
  			return match;
  	}
  	return NULL;
  }
  
  static int find_index_from_host_irq(struct kvm_assigned_dev_kernel
  				    *assigned_dev, int irq)
  {
  	int i, index;
  	struct msix_entry *host_msix_entries;
  
  	host_msix_entries = assigned_dev->host_msix_entries;
  
  	index = -1;
  	for (i = 0; i < assigned_dev->entries_nr; i++)
  		if (irq == host_msix_entries[i].vector) {
  			index = i;
  			break;
  		}
  	if (index < 0) {
  		printk(KERN_WARNING "Fail to find correlated MSI-X entry!
  ");
  		return 0;
  	}
  
  	return index;
  }
0645211c4   Jan Kiszka   KVM: Switch assig...
60
  static irqreturn_t kvm_assigned_dev_thread(int irq, void *dev_id)
bfd99ff5d   Avi Kivity   KVM: Move assigne...
61
  {
0645211c4   Jan Kiszka   KVM: Switch assig...
62
  	struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
63

0645211c4   Jan Kiszka   KVM: Switch assig...
64
65
66
67
68
69
  	if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_INTX) {
  		spin_lock(&assigned_dev->intx_lock);
  		disable_irq_nosync(irq);
  		assigned_dev->host_irq_disabled = true;
  		spin_unlock(&assigned_dev->intx_lock);
  	}
bfd99ff5d   Avi Kivity   KVM: Move assigne...
70

cc0793968   Jan Kiszka   KVM: Split up MSI...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  	kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
  		    assigned_dev->guest_irq, 1);
  
  	return IRQ_HANDLED;
  }
  
  #ifdef __KVM_HAVE_MSIX
  static irqreturn_t kvm_assigned_dev_thread_msix(int irq, void *dev_id)
  {
  	struct kvm_assigned_dev_kernel *assigned_dev = dev_id;
  	int index = find_index_from_host_irq(assigned_dev, irq);
  	u32 vector;
  
  	if (index >= 0) {
  		vector = assigned_dev->guest_msix_entries[index].vector;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
86
  		kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
cc0793968   Jan Kiszka   KVM: Split up MSI...
87
88
  			    vector, 1);
  	}
bfd99ff5d   Avi Kivity   KVM: Move assigne...
89

bfd99ff5d   Avi Kivity   KVM: Move assigne...
90
91
  	return IRQ_HANDLED;
  }
cc0793968   Jan Kiszka   KVM: Split up MSI...
92
  #endif
bfd99ff5d   Avi Kivity   KVM: Move assigne...
93
94
95
96
  
  /* Ack the irq line for an assigned device */
  static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
  {
c61fa9d63   Jan Kiszka   KVM: Avoid needle...
97
98
99
  	struct kvm_assigned_dev_kernel *dev =
  		container_of(kian, struct kvm_assigned_dev_kernel,
  			     ack_notifier);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
100
101
102
103
104
105
  
  	kvm_set_irq(dev->kvm, dev->irq_source_id, dev->guest_irq, 0);
  
  	/* The guest irq may be shared so this ack may be
  	 * from another device.
  	 */
0645211c4   Jan Kiszka   KVM: Switch assig...
106
  	spin_lock(&dev->intx_lock);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
107
108
109
110
  	if (dev->host_irq_disabled) {
  		enable_irq(dev->host_irq);
  		dev->host_irq_disabled = false;
  	}
0645211c4   Jan Kiszka   KVM: Switch assig...
111
  	spin_unlock(&dev->intx_lock);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
112
113
114
115
116
  }
  
  static void deassign_guest_irq(struct kvm *kvm,
  			       struct kvm_assigned_dev_kernel *assigned_dev)
  {
c61fa9d63   Jan Kiszka   KVM: Avoid needle...
117
118
119
  	if (assigned_dev->ack_notifier.gsi != -1)
  		kvm_unregister_irq_ack_notifier(kvm,
  						&assigned_dev->ack_notifier);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
120

0c106b5aa   Jan Kiszka   KVM: Clear assign...
121
122
  	kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
  		    assigned_dev->guest_irq, 0);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
123
124
125
126
127
128
129
130
131
132
133
  	if (assigned_dev->irq_source_id != -1)
  		kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
  	assigned_dev->irq_source_id = -1;
  	assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_GUEST_MASK);
  }
  
  /* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
  static void deassign_host_irq(struct kvm *kvm,
  			      struct kvm_assigned_dev_kernel *assigned_dev)
  {
  	/*
0645211c4   Jan Kiszka   KVM: Switch assig...
134
  	 * We disable irq here to prevent further events.
bfd99ff5d   Avi Kivity   KVM: Move assigne...
135
136
137
138
139
140
  	 *
  	 * Notice this maybe result in nested disable if the interrupt type is
  	 * INTx, but it's OK for we are going to free it.
  	 *
  	 * If this function is a part of VM destroy, please ensure that till
  	 * now, the kvm state is still legal for probably we also have to wait
0645211c4   Jan Kiszka   KVM: Switch assig...
141
  	 * on a currently running IRQ handler.
bfd99ff5d   Avi Kivity   KVM: Move assigne...
142
143
144
145
  	 */
  	if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSIX) {
  		int i;
  		for (i = 0; i < assigned_dev->entries_nr; i++)
0645211c4   Jan Kiszka   KVM: Switch assig...
146
  			disable_irq(assigned_dev->host_msix_entries[i].vector);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
147
148
149
  
  		for (i = 0; i < assigned_dev->entries_nr; i++)
  			free_irq(assigned_dev->host_msix_entries[i].vector,
9f9f6b787   Jan Kiszka   KVM: Clean up unn...
150
  				 assigned_dev);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
151
152
153
154
155
156
157
  
  		assigned_dev->entries_nr = 0;
  		kfree(assigned_dev->host_msix_entries);
  		kfree(assigned_dev->guest_msix_entries);
  		pci_disable_msix(assigned_dev->dev);
  	} else {
  		/* Deal with MSI and INTx */
0645211c4   Jan Kiszka   KVM: Switch assig...
158
  		disable_irq(assigned_dev->host_irq);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
159

9f9f6b787   Jan Kiszka   KVM: Clean up unn...
160
  		free_irq(assigned_dev->host_irq, assigned_dev);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  
  		if (assigned_dev->irq_requested_type & KVM_DEV_IRQ_HOST_MSI)
  			pci_disable_msi(assigned_dev->dev);
  	}
  
  	assigned_dev->irq_requested_type &= ~(KVM_DEV_IRQ_HOST_MASK);
  }
  
  static int kvm_deassign_irq(struct kvm *kvm,
  			    struct kvm_assigned_dev_kernel *assigned_dev,
  			    unsigned long irq_requested_type)
  {
  	unsigned long guest_irq_type, host_irq_type;
  
  	if (!irqchip_in_kernel(kvm))
  		return -EINVAL;
  	/* no irq assignment to deassign */
  	if (!assigned_dev->irq_requested_type)
  		return -ENXIO;
  
  	host_irq_type = irq_requested_type & KVM_DEV_IRQ_HOST_MASK;
  	guest_irq_type = irq_requested_type & KVM_DEV_IRQ_GUEST_MASK;
  
  	if (host_irq_type)
  		deassign_host_irq(kvm, assigned_dev);
  	if (guest_irq_type)
  		deassign_guest_irq(kvm, assigned_dev);
  
  	return 0;
  }
  
  static void kvm_free_assigned_irq(struct kvm *kvm,
  				  struct kvm_assigned_dev_kernel *assigned_dev)
  {
  	kvm_deassign_irq(kvm, assigned_dev, assigned_dev->irq_requested_type);
  }
  
  static void kvm_free_assigned_device(struct kvm *kvm,
  				     struct kvm_assigned_dev_kernel
  				     *assigned_dev)
  {
  	kvm_free_assigned_irq(kvm, assigned_dev);
f8fcfd775   Alex Williamson   KVM: Use pci_stor...
203
204
205
206
207
208
209
210
  	pci_reset_function(assigned_dev->dev);
  	if (pci_load_and_free_saved_state(assigned_dev->dev,
  					  &assigned_dev->pci_saved_state))
  		printk(KERN_INFO "%s: Couldn't reload %s saved state
  ",
  		       __func__, dev_name(&assigned_dev->dev->dev));
  	else
  		pci_restore_state(assigned_dev->dev);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
211

6777829cf   Greg Rose   pci: Add flag ind...
212
  	assigned_dev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  	pci_release_regions(assigned_dev->dev);
  	pci_disable_device(assigned_dev->dev);
  	pci_dev_put(assigned_dev->dev);
  
  	list_del(&assigned_dev->list);
  	kfree(assigned_dev);
  }
  
  void kvm_free_all_assigned_devices(struct kvm *kvm)
  {
  	struct list_head *ptr, *ptr2;
  	struct kvm_assigned_dev_kernel *assigned_dev;
  
  	list_for_each_safe(ptr, ptr2, &kvm->arch.assigned_dev_head) {
  		assigned_dev = list_entry(ptr,
  					  struct kvm_assigned_dev_kernel,
  					  list);
  
  		kvm_free_assigned_device(kvm, assigned_dev);
  	}
  }
  
  static int assigned_device_enable_host_intx(struct kvm *kvm,
  					    struct kvm_assigned_dev_kernel *dev)
  {
  	dev->host_irq = dev->dev->irq;
  	/* Even though this is PCI, we don't want to use shared
  	 * interrupts. Sharing host devices with guest-assigned devices
  	 * on the same interrupt line is not a happy situation: there
  	 * are going to be long delays in accepting, acking, etc.
  	 */
0645211c4   Jan Kiszka   KVM: Switch assig...
244
  	if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
9f9f6b787   Jan Kiszka   KVM: Clean up unn...
245
  				 IRQF_ONESHOT, dev->irq_name, dev))
bfd99ff5d   Avi Kivity   KVM: Move assigne...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  		return -EIO;
  	return 0;
  }
  
  #ifdef __KVM_HAVE_MSI
  static int assigned_device_enable_host_msi(struct kvm *kvm,
  					   struct kvm_assigned_dev_kernel *dev)
  {
  	int r;
  
  	if (!dev->dev->msi_enabled) {
  		r = pci_enable_msi(dev->dev);
  		if (r)
  			return r;
  	}
  
  	dev->host_irq = dev->dev->irq;
0645211c4   Jan Kiszka   KVM: Switch assig...
263
  	if (request_threaded_irq(dev->host_irq, NULL, kvm_assigned_dev_thread,
9f9f6b787   Jan Kiszka   KVM: Clean up unn...
264
  				 0, dev->irq_name, dev)) {
bfd99ff5d   Avi Kivity   KVM: Move assigne...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  		pci_disable_msi(dev->dev);
  		return -EIO;
  	}
  
  	return 0;
  }
  #endif
  
  #ifdef __KVM_HAVE_MSIX
  static int assigned_device_enable_host_msix(struct kvm *kvm,
  					    struct kvm_assigned_dev_kernel *dev)
  {
  	int i, r = -EINVAL;
  
  	/* host_msix_entries and guest_msix_entries should have been
  	 * initialized */
  	if (dev->entries_nr == 0)
  		return r;
  
  	r = pci_enable_msix(dev->dev, dev->host_msix_entries, dev->entries_nr);
  	if (r)
  		return r;
  
  	for (i = 0; i < dev->entries_nr; i++) {
0645211c4   Jan Kiszka   KVM: Switch assig...
289
  		r = request_threaded_irq(dev->host_msix_entries[i].vector,
cc0793968   Jan Kiszka   KVM: Split up MSI...
290
  					 NULL, kvm_assigned_dev_thread_msix,
9f9f6b787   Jan Kiszka   KVM: Clean up unn...
291
  					 0, dev->irq_name, dev);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
292
  		if (r)
d57e2c074   jing zhang   KVM: fix assigned...
293
  			goto err;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
294
295
296
  	}
  
  	return 0;
d57e2c074   jing zhang   KVM: fix assigned...
297
298
  err:
  	for (i -= 1; i >= 0; i--)
9f9f6b787   Jan Kiszka   KVM: Clean up unn...
299
  		free_irq(dev->host_msix_entries[i].vector, dev);
d57e2c074   jing zhang   KVM: fix assigned...
300
301
  	pci_disable_msix(dev->dev);
  	return r;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
  }
  
  #endif
  
  static int assigned_device_enable_guest_intx(struct kvm *kvm,
  				struct kvm_assigned_dev_kernel *dev,
  				struct kvm_assigned_irq *irq)
  {
  	dev->guest_irq = irq->guest_irq;
  	dev->ack_notifier.gsi = irq->guest_irq;
  	return 0;
  }
  
  #ifdef __KVM_HAVE_MSI
  static int assigned_device_enable_guest_msi(struct kvm *kvm,
  			struct kvm_assigned_dev_kernel *dev,
  			struct kvm_assigned_irq *irq)
  {
  	dev->guest_irq = irq->guest_irq;
  	dev->ack_notifier.gsi = -1;
  	dev->host_irq_disabled = false;
  	return 0;
  }
  #endif
  
  #ifdef __KVM_HAVE_MSIX
  static int assigned_device_enable_guest_msix(struct kvm *kvm,
  			struct kvm_assigned_dev_kernel *dev,
  			struct kvm_assigned_irq *irq)
  {
  	dev->guest_irq = irq->guest_irq;
  	dev->ack_notifier.gsi = -1;
  	dev->host_irq_disabled = false;
  	return 0;
  }
  #endif
  
  static int assign_host_irq(struct kvm *kvm,
  			   struct kvm_assigned_dev_kernel *dev,
  			   __u32 host_irq_type)
  {
  	int r = -EEXIST;
  
  	if (dev->irq_requested_type & KVM_DEV_IRQ_HOST_MASK)
  		return r;
1e001d49f   Jan Kiszka   KVM: Refactor IRQ...
347
348
  	snprintf(dev->irq_name, sizeof(dev->irq_name), "kvm:%s",
  		 pci_name(dev->dev));
bfd99ff5d   Avi Kivity   KVM: Move assigne...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  	switch (host_irq_type) {
  	case KVM_DEV_IRQ_HOST_INTX:
  		r = assigned_device_enable_host_intx(kvm, dev);
  		break;
  #ifdef __KVM_HAVE_MSI
  	case KVM_DEV_IRQ_HOST_MSI:
  		r = assigned_device_enable_host_msi(kvm, dev);
  		break;
  #endif
  #ifdef __KVM_HAVE_MSIX
  	case KVM_DEV_IRQ_HOST_MSIX:
  		r = assigned_device_enable_host_msix(kvm, dev);
  		break;
  #endif
  	default:
  		r = -EINVAL;
  	}
  
  	if (!r)
  		dev->irq_requested_type |= host_irq_type;
  
  	return r;
  }
  
  static int assign_guest_irq(struct kvm *kvm,
  			    struct kvm_assigned_dev_kernel *dev,
  			    struct kvm_assigned_irq *irq,
  			    unsigned long guest_irq_type)
  {
  	int id;
  	int r = -EEXIST;
  
  	if (dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MASK)
  		return r;
  
  	id = kvm_request_irq_source_id(kvm);
  	if (id < 0)
  		return id;
  
  	dev->irq_source_id = id;
  
  	switch (guest_irq_type) {
  	case KVM_DEV_IRQ_GUEST_INTX:
  		r = assigned_device_enable_guest_intx(kvm, dev, irq);
  		break;
  #ifdef __KVM_HAVE_MSI
  	case KVM_DEV_IRQ_GUEST_MSI:
  		r = assigned_device_enable_guest_msi(kvm, dev, irq);
  		break;
  #endif
  #ifdef __KVM_HAVE_MSIX
  	case KVM_DEV_IRQ_GUEST_MSIX:
  		r = assigned_device_enable_guest_msix(kvm, dev, irq);
  		break;
  #endif
  	default:
  		r = -EINVAL;
  	}
  
  	if (!r) {
  		dev->irq_requested_type |= guest_irq_type;
c61fa9d63   Jan Kiszka   KVM: Avoid needle...
410
411
  		if (dev->ack_notifier.gsi != -1)
  			kvm_register_irq_ack_notifier(kvm, &dev->ack_notifier);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
412
413
414
415
416
417
418
419
420
421
422
423
424
  	} else
  		kvm_free_irq_source_id(kvm, dev->irq_source_id);
  
  	return r;
  }
  
  /* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
  static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
  				   struct kvm_assigned_irq *assigned_irq)
  {
  	int r = -EINVAL;
  	struct kvm_assigned_dev_kernel *match;
  	unsigned long host_irq_type, guest_irq_type;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	if (!irqchip_in_kernel(kvm))
  		return r;
  
  	mutex_lock(&kvm->lock);
  	r = -ENODEV;
  	match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      assigned_irq->assigned_dev_id);
  	if (!match)
  		goto out;
  
  	host_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_HOST_MASK);
  	guest_irq_type = (assigned_irq->flags & KVM_DEV_IRQ_GUEST_MASK);
  
  	r = -EINVAL;
  	/* can only assign one type at a time */
  	if (hweight_long(host_irq_type) > 1)
  		goto out;
  	if (hweight_long(guest_irq_type) > 1)
  		goto out;
  	if (host_irq_type == 0 && guest_irq_type == 0)
  		goto out;
  
  	r = 0;
  	if (host_irq_type)
  		r = assign_host_irq(kvm, match, host_irq_type);
  	if (r)
  		goto out;
  
  	if (guest_irq_type)
  		r = assign_guest_irq(kvm, match, assigned_irq, guest_irq_type);
  out:
  	mutex_unlock(&kvm->lock);
  	return r;
  }
  
  static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm,
  					 struct kvm_assigned_irq
  					 *assigned_irq)
  {
  	int r = -ENODEV;
  	struct kvm_assigned_dev_kernel *match;
  
  	mutex_lock(&kvm->lock);
  
  	match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      assigned_irq->assigned_dev_id);
  	if (!match)
  		goto out;
  
  	r = kvm_deassign_irq(kvm, match, assigned_irq->flags);
  out:
  	mutex_unlock(&kvm->lock);
  	return r;
  }
3d27e23b1   Alex Williamson   KVM: Device assig...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  /*
   * We want to test whether the caller has been granted permissions to
   * use this device.  To be able to configure and control the device,
   * the user needs access to PCI configuration space and BAR resources.
   * These are accessed through PCI sysfs.  PCI config space is often
   * passed to the process calling this ioctl via file descriptor, so we
   * can't rely on access to that file.  We can check for permissions
   * on each of the BAR resource files, which is a pretty clear
   * indicator that the user has been granted access to the device.
   */
  static int probe_sysfs_permissions(struct pci_dev *dev)
  {
  #ifdef CONFIG_SYSFS
  	int i;
  	bool bar_found = false;
  
  	for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++) {
  		char *kpath, *syspath;
  		struct path path;
  		struct inode *inode;
  		int r;
  
  		if (!pci_resource_len(dev, i))
  			continue;
  
  		kpath = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
  		if (!kpath)
  			return -ENOMEM;
  
  		/* Per sysfs-rules, sysfs is always at /sys */
  		syspath = kasprintf(GFP_KERNEL, "/sys%s/resource%d", kpath, i);
  		kfree(kpath);
  		if (!syspath)
  			return -ENOMEM;
  
  		r = kern_path(syspath, LOOKUP_FOLLOW, &path);
  		kfree(syspath);
  		if (r)
  			return r;
  
  		inode = path.dentry->d_inode;
  
  		r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS);
  		path_put(&path);
  		if (r)
  			return r;
  
  		bar_found = true;
  	}
  
  	/* If no resources, probably something special */
  	if (!bar_found)
  		return -EPERM;
  
  	return 0;
  #else
  	return -EINVAL; /* No way to control the device without sysfs */
  #endif
  }
bfd99ff5d   Avi Kivity   KVM: Move assigne...
538
539
540
  static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
  				      struct kvm_assigned_pci_dev *assigned_dev)
  {
bc6678a33   Marcelo Tosatti   KVM: introduce kv...
541
  	int r = 0, idx;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
542
543
  	struct kvm_assigned_dev_kernel *match;
  	struct pci_dev *dev;
3d27e23b1   Alex Williamson   KVM: Device assig...
544
  	u8 header_type;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
545

423873736   Alex Williamson   KVM: Remove abili...
546
547
  	if (!(assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU))
  		return -EINVAL;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
548
  	mutex_lock(&kvm->lock);
bc6678a33   Marcelo Tosatti   KVM: introduce kv...
549
  	idx = srcu_read_lock(&kvm->srcu);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  
  	match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      assigned_dev->assigned_dev_id);
  	if (match) {
  		/* device already assigned */
  		r = -EEXIST;
  		goto out;
  	}
  
  	match = kzalloc(sizeof(struct kvm_assigned_dev_kernel), GFP_KERNEL);
  	if (match == NULL) {
  		printk(KERN_INFO "%s: Couldn't allocate memory
  ",
  		       __func__);
  		r = -ENOMEM;
  		goto out;
  	}
ab9f4ecbb   Zhai, Edwin   KVM: enable PCI m...
567
568
  	dev = pci_get_domain_bus_and_slot(assigned_dev->segnr,
  				   assigned_dev->busnr,
bfd99ff5d   Avi Kivity   KVM: Move assigne...
569
570
571
572
573
574
575
  				   assigned_dev->devfn);
  	if (!dev) {
  		printk(KERN_INFO "%s: host device not found
  ", __func__);
  		r = -EINVAL;
  		goto out_free;
  	}
3d27e23b1   Alex Williamson   KVM: Device assig...
576
577
578
579
580
581
582
583
584
585
586
  
  	/* Don't allow bridges to be assigned */
  	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
  	if ((header_type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL) {
  		r = -EPERM;
  		goto out_put;
  	}
  
  	r = probe_sysfs_permissions(dev);
  	if (r)
  		goto out_put;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  	if (pci_enable_device(dev)) {
  		printk(KERN_INFO "%s: Could not enable PCI device
  ", __func__);
  		r = -EBUSY;
  		goto out_put;
  	}
  	r = pci_request_regions(dev, "kvm_assigned_device");
  	if (r) {
  		printk(KERN_INFO "%s: Could not get access to device regions
  ",
  		       __func__);
  		goto out_disable;
  	}
  
  	pci_reset_function(dev);
ed78661f2   Jan Kiszka   KVM: Save/restore...
602
  	pci_save_state(dev);
f8fcfd775   Alex Williamson   KVM: Use pci_stor...
603
604
605
606
607
  	match->pci_saved_state = pci_store_saved_state(dev);
  	if (!match->pci_saved_state)
  		printk(KERN_DEBUG "%s: Couldn't store %s saved state
  ",
  		       __func__, dev_name(&dev->dev));
bfd99ff5d   Avi Kivity   KVM: Move assigne...
608
  	match->assigned_dev_id = assigned_dev->assigned_dev_id;
ab9f4ecbb   Zhai, Edwin   KVM: enable PCI m...
609
  	match->host_segnr = assigned_dev->segnr;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
610
611
612
613
  	match->host_busnr = assigned_dev->busnr;
  	match->host_devfn = assigned_dev->devfn;
  	match->flags = assigned_dev->flags;
  	match->dev = dev;
0645211c4   Jan Kiszka   KVM: Switch assig...
614
  	spin_lock_init(&match->intx_lock);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
615
616
617
  	match->irq_source_id = -1;
  	match->kvm = kvm;
  	match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
618
619
  
  	list_add(&match->list, &kvm->arch.assigned_dev_head);
423873736   Alex Williamson   KVM: Remove abili...
620
621
  	if (!kvm->arch.iommu_domain) {
  		r = kvm_iommu_map_guest(kvm);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
622
623
624
  		if (r)
  			goto out_list_del;
  	}
423873736   Alex Williamson   KVM: Remove abili...
625
626
627
  	r = kvm_assign_device(kvm, match);
  	if (r)
  		goto out_list_del;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
628
629
  
  out:
bc6678a33   Marcelo Tosatti   KVM: introduce kv...
630
  	srcu_read_unlock(&kvm->srcu, idx);
fae3a3536   Sheng Yang   KVM: Fix possible...
631
  	mutex_unlock(&kvm->lock);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
632
633
  	return r;
  out_list_del:
f8fcfd775   Alex Williamson   KVM: Use pci_stor...
634
635
636
637
  	if (pci_load_and_free_saved_state(dev, &match->pci_saved_state))
  		printk(KERN_INFO "%s: Couldn't reload %s saved state
  ",
  		       __func__, dev_name(&dev->dev));
bfd99ff5d   Avi Kivity   KVM: Move assigne...
638
639
640
641
642
643
644
645
  	list_del(&match->list);
  	pci_release_regions(dev);
  out_disable:
  	pci_disable_device(dev);
  out_put:
  	pci_dev_put(dev);
  out_free:
  	kfree(match);
bc6678a33   Marcelo Tosatti   KVM: introduce kv...
646
  	srcu_read_unlock(&kvm->srcu, idx);
fae3a3536   Sheng Yang   KVM: Fix possible...
647
  	mutex_unlock(&kvm->lock);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  	return r;
  }
  
  static int kvm_vm_ioctl_deassign_device(struct kvm *kvm,
  		struct kvm_assigned_pci_dev *assigned_dev)
  {
  	int r = 0;
  	struct kvm_assigned_dev_kernel *match;
  
  	mutex_lock(&kvm->lock);
  
  	match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      assigned_dev->assigned_dev_id);
  	if (!match) {
  		printk(KERN_INFO "%s: device hasn't been assigned before, "
  		  "so cannot be deassigned
  ", __func__);
  		r = -EINVAL;
  		goto out;
  	}
423873736   Alex Williamson   KVM: Remove abili...
668
  	kvm_deassign_device(kvm, match);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
  
  	kvm_free_assigned_device(kvm, match);
  
  out:
  	mutex_unlock(&kvm->lock);
  	return r;
  }
  
  
  #ifdef __KVM_HAVE_MSIX
  static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm,
  				    struct kvm_assigned_msix_nr *entry_nr)
  {
  	int r = 0;
  	struct kvm_assigned_dev_kernel *adev;
  
  	mutex_lock(&kvm->lock);
  
  	adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      entry_nr->assigned_dev_id);
  	if (!adev) {
  		r = -EINVAL;
  		goto msix_nr_out;
  	}
  
  	if (adev->entries_nr == 0) {
  		adev->entries_nr = entry_nr->entry_nr;
  		if (adev->entries_nr == 0 ||
9f3191aec   Jan Kiszka   KVM: Fix off-by-o...
697
  		    adev->entries_nr > KVM_MAX_MSIX_PER_DEV) {
bfd99ff5d   Avi Kivity   KVM: Move assigne...
698
699
700
701
702
703
704
705
706
707
708
  			r = -EINVAL;
  			goto msix_nr_out;
  		}
  
  		adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) *
  						entry_nr->entry_nr,
  						GFP_KERNEL);
  		if (!adev->host_msix_entries) {
  			r = -ENOMEM;
  			goto msix_nr_out;
  		}
0645211c4   Jan Kiszka   KVM: Switch assig...
709
710
711
  		adev->guest_msix_entries =
  			kzalloc(sizeof(struct msix_entry) * entry_nr->entry_nr,
  				GFP_KERNEL);
bfd99ff5d   Avi Kivity   KVM: Move assigne...
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  		if (!adev->guest_msix_entries) {
  			kfree(adev->host_msix_entries);
  			r = -ENOMEM;
  			goto msix_nr_out;
  		}
  	} else /* Not allowed set MSI-X number twice */
  		r = -EINVAL;
  msix_nr_out:
  	mutex_unlock(&kvm->lock);
  	return r;
  }
  
  static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm,
  				       struct kvm_assigned_msix_entry *entry)
  {
  	int r = 0, i;
  	struct kvm_assigned_dev_kernel *adev;
  
  	mutex_lock(&kvm->lock);
  
  	adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
  				      entry->assigned_dev_id);
  
  	if (!adev) {
  		r = -EINVAL;
  		goto msix_entry_out;
  	}
  
  	for (i = 0; i < adev->entries_nr; i++)
  		if (adev->guest_msix_entries[i].vector == 0 ||
  		    adev->guest_msix_entries[i].entry == entry->entry) {
  			adev->guest_msix_entries[i].entry = entry->entry;
  			adev->guest_msix_entries[i].vector = entry->gsi;
  			adev->host_msix_entries[i].entry = entry->entry;
  			break;
  		}
  	if (i == adev->entries_nr) {
  		r = -ENOSPC;
  		goto msix_entry_out;
  	}
  
  msix_entry_out:
  	mutex_unlock(&kvm->lock);
  
  	return r;
  }
  #endif
  
  long kvm_vm_ioctl_assigned_device(struct kvm *kvm, unsigned ioctl,
  				  unsigned long arg)
  {
  	void __user *argp = (void __user *)arg;
51de271d4   Jan Kiszka   KVM: Clean up kvm...
764
  	int r;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
  
  	switch (ioctl) {
  	case KVM_ASSIGN_PCI_DEVICE: {
  		struct kvm_assigned_pci_dev assigned_dev;
  
  		r = -EFAULT;
  		if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
  			goto out;
  		r = kvm_vm_ioctl_assign_device(kvm, &assigned_dev);
  		if (r)
  			goto out;
  		break;
  	}
  	case KVM_ASSIGN_IRQ: {
  		r = -EOPNOTSUPP;
  		break;
  	}
bfd99ff5d   Avi Kivity   KVM: Move assigne...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  	case KVM_ASSIGN_DEV_IRQ: {
  		struct kvm_assigned_irq assigned_irq;
  
  		r = -EFAULT;
  		if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
  			goto out;
  		r = kvm_vm_ioctl_assign_irq(kvm, &assigned_irq);
  		if (r)
  			goto out;
  		break;
  	}
  	case KVM_DEASSIGN_DEV_IRQ: {
  		struct kvm_assigned_irq assigned_irq;
  
  		r = -EFAULT;
  		if (copy_from_user(&assigned_irq, argp, sizeof assigned_irq))
  			goto out;
  		r = kvm_vm_ioctl_deassign_dev_irq(kvm, &assigned_irq);
  		if (r)
  			goto out;
  		break;
  	}
bfd99ff5d   Avi Kivity   KVM: Move assigne...
804
805
806
807
808
809
810
811
812
813
814
  	case KVM_DEASSIGN_PCI_DEVICE: {
  		struct kvm_assigned_pci_dev assigned_dev;
  
  		r = -EFAULT;
  		if (copy_from_user(&assigned_dev, argp, sizeof assigned_dev))
  			goto out;
  		r = kvm_vm_ioctl_deassign_device(kvm, &assigned_dev);
  		if (r)
  			goto out;
  		break;
  	}
bfd99ff5d   Avi Kivity   KVM: Move assigne...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
  #ifdef KVM_CAP_IRQ_ROUTING
  	case KVM_SET_GSI_ROUTING: {
  		struct kvm_irq_routing routing;
  		struct kvm_irq_routing __user *urouting;
  		struct kvm_irq_routing_entry *entries;
  
  		r = -EFAULT;
  		if (copy_from_user(&routing, argp, sizeof(routing)))
  			goto out;
  		r = -EINVAL;
  		if (routing.nr >= KVM_MAX_IRQ_ROUTES)
  			goto out;
  		if (routing.flags)
  			goto out;
  		r = -ENOMEM;
  		entries = vmalloc(routing.nr * sizeof(*entries));
  		if (!entries)
  			goto out;
  		r = -EFAULT;
  		urouting = argp;
  		if (copy_from_user(entries, urouting->entries,
  				   routing.nr * sizeof(*entries)))
  			goto out_free_irq_routing;
  		r = kvm_set_irq_routing(kvm, entries, routing.nr,
  					routing.flags);
  	out_free_irq_routing:
  		vfree(entries);
  		break;
  	}
  #endif /* KVM_CAP_IRQ_ROUTING */
  #ifdef __KVM_HAVE_MSIX
  	case KVM_ASSIGN_SET_MSIX_NR: {
  		struct kvm_assigned_msix_nr entry_nr;
  		r = -EFAULT;
  		if (copy_from_user(&entry_nr, argp, sizeof entry_nr))
  			goto out;
  		r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr);
  		if (r)
  			goto out;
  		break;
  	}
  	case KVM_ASSIGN_SET_MSIX_ENTRY: {
  		struct kvm_assigned_msix_entry entry;
  		r = -EFAULT;
  		if (copy_from_user(&entry, argp, sizeof entry))
  			goto out;
  		r = kvm_vm_ioctl_set_msix_entry(kvm, &entry);
  		if (r)
  			goto out;
  		break;
  	}
  #endif
51de271d4   Jan Kiszka   KVM: Clean up kvm...
867
868
869
  	default:
  		r = -ENOTTY;
  		break;
bfd99ff5d   Avi Kivity   KVM: Move assigne...
870
871
872
873
  	}
  out:
  	return r;
  }