Skip to content

Commit 7a84428

Browse files
awilliamavikivity
authored andcommittedSep 23, 2012
KVM: Add resampling irqfds for level triggered interrupts
To emulate level triggered interrupts, add a resample option to KVM_IRQFD. When specified, a new resamplefd is provided that notifies the user when the irqchip has been resampled by the VM. This may, for instance, indicate an EOI. Also in this mode, posting of an interrupt through an irqfd only asserts the interrupt. On resampling, the interrupt is automatically de-asserted prior to user notification. This enables level triggered interrupts to be posted and re-enabled from vfio with no userspace intervention. All resampling irqfds can make use of a single irq source ID, so we reserve a new one for this interface. Signed-off-by: Alex Williamson <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent 1e08ec4 commit 7a84428

File tree

6 files changed

+184
-6
lines changed

6 files changed

+184
-6
lines changed
 

‎Documentation/virtual/kvm/api.txt

+13
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,19 @@ the guest using the specified gsi pin. The irqfd is removed using
19501950
the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
19511951
and kvm_irqfd.gsi.
19521952

1953+
With KVM_CAP_IRQFD_RESAMPLE, KVM_IRQFD supports a de-assert and notify
1954+
mechanism allowing emulation of level-triggered, irqfd-based
1955+
interrupts. When KVM_IRQFD_FLAG_RESAMPLE is set the user must pass an
1956+
additional eventfd in the kvm_irqfd.resamplefd field. When operating
1957+
in resample mode, posting of an interrupt through kvm_irq.fd asserts
1958+
the specified gsi in the irqchip. When the irqchip is resampled, such
1959+
as from an EOI, the gsi is de-asserted and the user is notifed via
1960+
kvm_irqfd.resamplefd. It is the user's responsibility to re-queue
1961+
the interrupt if the device making use of it still requires service.
1962+
Note that closing the resamplefd is not sufficient to disable the
1963+
irqfd. The KVM_IRQFD_FLAG_RESAMPLE is only necessary on assignment
1964+
and need not be specified with KVM_IRQFD_FLAG_DEASSIGN.
1965+
19531966
4.76 KVM_PPC_ALLOCATE_HTAB
19541967

19551968
Capability: KVM_CAP_PPC_ALLOC_HTAB

‎arch/x86/kvm/x86.c

+4
Original file line numberDiff line numberDiff line change
@@ -2176,6 +2176,7 @@ int kvm_dev_ioctl_check_extension(long ext)
21762176
case KVM_CAP_PCI_2_3:
21772177
case KVM_CAP_KVMCLOCK_CTRL:
21782178
case KVM_CAP_READONLY_MEM:
2179+
case KVM_CAP_IRQFD_RESAMPLE:
21792180
r = 1;
21802181
break;
21812182
case KVM_CAP_COALESCED_MMIO:
@@ -6268,6 +6269,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
62686269

62696270
/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
62706271
set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
6272+
/* Reserve bit 1 of irq_sources_bitmap for irqfd-resampler */
6273+
set_bit(KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
6274+
&kvm->arch.irq_sources_bitmap);
62716275

62726276
raw_spin_lock_init(&kvm->arch.tsc_write_lock);
62736277
mutex_init(&kvm->arch.apic_map_lock);

‎include/linux/kvm.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ struct kvm_ppc_smmu_info {
625625
#ifdef __KVM_HAVE_READONLY_MEM
626626
#define KVM_CAP_READONLY_MEM 81
627627
#endif
628+
#define KVM_CAP_IRQFD_RESAMPLE 82
628629

629630
#ifdef KVM_CAP_IRQ_ROUTING
630631

@@ -690,12 +691,21 @@ struct kvm_xen_hvm_config {
690691
#endif
691692

692693
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
694+
/*
695+
* Available with KVM_CAP_IRQFD_RESAMPLE
696+
*
697+
* KVM_IRQFD_FLAG_RESAMPLE indicates resamplefd is valid and specifies
698+
* the irqfd to operate in resampling mode for level triggered interrupt
699+
* emlation. See Documentation/virtual/kvm/api.txt.
700+
*/
701+
#define KVM_IRQFD_FLAG_RESAMPLE (1 << 1)
693702

694703
struct kvm_irqfd {
695704
__u32 fd;
696705
__u32 gsi;
697706
__u32 flags;
698-
__u8 pad[20];
707+
__u32 resamplefd;
708+
__u8 pad[16];
699709
};
700710

701711
struct kvm_clock_data {

‎include/linux/kvm_host.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ static inline bool is_error_page(struct page *page)
119119
#define KVM_REQ_PMU 16
120120
#define KVM_REQ_PMI 17
121121

122-
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
122+
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
123+
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
123124

124125
struct kvm;
125126
struct kvm_vcpu;
@@ -343,6 +344,8 @@ struct kvm {
343344
struct {
344345
spinlock_t lock;
345346
struct list_head items;
347+
struct list_head resampler_list;
348+
struct mutex resampler_lock;
346349
} irqfds;
347350
struct list_head ioeventfds;
348351
#endif

‎virt/kvm/eventfd.c

+146-4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,31 @@
4343
* --------------------------------------------------------------------
4444
*/
4545

46+
/*
47+
* Resampling irqfds are a special variety of irqfds used to emulate
48+
* level triggered interrupts. The interrupt is asserted on eventfd
49+
* trigger. On acknowledgement through the irq ack notifier, the
50+
* interrupt is de-asserted and userspace is notified through the
51+
* resamplefd. All resamplers on the same gsi are de-asserted
52+
* together, so we don't need to track the state of each individual
53+
* user. We can also therefore share the same irq source ID.
54+
*/
55+
struct _irqfd_resampler {
56+
struct kvm *kvm;
57+
/*
58+
* List of resampling struct _irqfd objects sharing this gsi.
59+
* RCU list modified under kvm->irqfds.resampler_lock
60+
*/
61+
struct list_head list;
62+
struct kvm_irq_ack_notifier notifier;
63+
/*
64+
* Entry in list of kvm->irqfd.resampler_list. Use for sharing
65+
* resamplers among irqfds on the same gsi.
66+
* Accessed and modified under kvm->irqfds.resampler_lock
67+
*/
68+
struct list_head link;
69+
};
70+
4671
struct _irqfd {
4772
/* Used for MSI fast-path */
4873
struct kvm *kvm;
@@ -52,6 +77,12 @@ struct _irqfd {
5277
/* Used for level IRQ fast-path */
5378
int gsi;
5479
struct work_struct inject;
80+
/* The resampler used by this irqfd (resampler-only) */
81+
struct _irqfd_resampler *resampler;
82+
/* Eventfd notified on resample (resampler-only) */
83+
struct eventfd_ctx *resamplefd;
84+
/* Entry in list of irqfds for a resampler (resampler-only) */
85+
struct list_head resampler_link;
5586
/* Used for setup/shutdown */
5687
struct eventfd_ctx *eventfd;
5788
struct list_head list;
@@ -67,8 +98,58 @@ irqfd_inject(struct work_struct *work)
6798
struct _irqfd *irqfd = container_of(work, struct _irqfd, inject);
6899
struct kvm *kvm = irqfd->kvm;
69100

70-
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1);
71-
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0);
101+
if (!irqfd->resampler) {
102+
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1);
103+
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0);
104+
} else
105+
kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
106+
irqfd->gsi, 1);
107+
}
108+
109+
/*
110+
* Since resampler irqfds share an IRQ source ID, we de-assert once
111+
* then notify all of the resampler irqfds using this GSI. We can't
112+
* do multiple de-asserts or we risk racing with incoming re-asserts.
113+
*/
114+
static void
115+
irqfd_resampler_ack(struct kvm_irq_ack_notifier *kian)
116+
{
117+
struct _irqfd_resampler *resampler;
118+
struct _irqfd *irqfd;
119+
120+
resampler = container_of(kian, struct _irqfd_resampler, notifier);
121+
122+
kvm_set_irq(resampler->kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
123+
resampler->notifier.gsi, 0);
124+
125+
rcu_read_lock();
126+
127+
list_for_each_entry_rcu(irqfd, &resampler->list, resampler_link)
128+
eventfd_signal(irqfd->resamplefd, 1);
129+
130+
rcu_read_unlock();
131+
}
132+
133+
static void
134+
irqfd_resampler_shutdown(struct _irqfd *irqfd)
135+
{
136+
struct _irqfd_resampler *resampler = irqfd->resampler;
137+
struct kvm *kvm = resampler->kvm;
138+
139+
mutex_lock(&kvm->irqfds.resampler_lock);
140+
141+
list_del_rcu(&irqfd->resampler_link);
142+
synchronize_rcu();
143+
144+
if (list_empty(&resampler->list)) {
145+
list_del(&resampler->link);
146+
kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier);
147+
kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
148+
resampler->notifier.gsi, 0);
149+
kfree(resampler);
150+
}
151+
152+
mutex_unlock(&kvm->irqfds.resampler_lock);
72153
}
73154

74155
/*
@@ -92,6 +173,11 @@ irqfd_shutdown(struct work_struct *work)
92173
*/
93174
flush_work_sync(&irqfd->inject);
94175

176+
if (irqfd->resampler) {
177+
irqfd_resampler_shutdown(irqfd);
178+
eventfd_ctx_put(irqfd->resamplefd);
179+
}
180+
95181
/*
96182
* It is now safe to release the object's resources
97183
*/
@@ -203,7 +289,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
203289
struct kvm_irq_routing_table *irq_rt;
204290
struct _irqfd *irqfd, *tmp;
205291
struct file *file = NULL;
206-
struct eventfd_ctx *eventfd = NULL;
292+
struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
207293
int ret;
208294
unsigned int events;
209295

@@ -231,6 +317,54 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
231317

232318
irqfd->eventfd = eventfd;
233319

320+
if (args->flags & KVM_IRQFD_FLAG_RESAMPLE) {
321+
struct _irqfd_resampler *resampler;
322+
323+
resamplefd = eventfd_ctx_fdget(args->resamplefd);
324+
if (IS_ERR(resamplefd)) {
325+
ret = PTR_ERR(resamplefd);
326+
goto fail;
327+
}
328+
329+
irqfd->resamplefd = resamplefd;
330+
INIT_LIST_HEAD(&irqfd->resampler_link);
331+
332+
mutex_lock(&kvm->irqfds.resampler_lock);
333+
334+
list_for_each_entry(resampler,
335+
&kvm->irqfds.resampler_list, list) {
336+
if (resampler->notifier.gsi == irqfd->gsi) {
337+
irqfd->resampler = resampler;
338+
break;
339+
}
340+
}
341+
342+
if (!irqfd->resampler) {
343+
resampler = kzalloc(sizeof(*resampler), GFP_KERNEL);
344+
if (!resampler) {
345+
ret = -ENOMEM;
346+
mutex_unlock(&kvm->irqfds.resampler_lock);
347+
goto fail;
348+
}
349+
350+
resampler->kvm = kvm;
351+
INIT_LIST_HEAD(&resampler->list);
352+
resampler->notifier.gsi = irqfd->gsi;
353+
resampler->notifier.irq_acked = irqfd_resampler_ack;
354+
INIT_LIST_HEAD(&resampler->link);
355+
356+
list_add(&resampler->link, &kvm->irqfds.resampler_list);
357+
kvm_register_irq_ack_notifier(kvm,
358+
&resampler->notifier);
359+
irqfd->resampler = resampler;
360+
}
361+
362+
list_add_rcu(&irqfd->resampler_link, &irqfd->resampler->list);
363+
synchronize_rcu();
364+
365+
mutex_unlock(&kvm->irqfds.resampler_lock);
366+
}
367+
234368
/*
235369
* Install our own custom wake-up handling so we are notified via
236370
* a callback whenever someone signals the underlying eventfd
@@ -276,6 +410,12 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
276410
return 0;
277411

278412
fail:
413+
if (irqfd->resampler)
414+
irqfd_resampler_shutdown(irqfd);
415+
416+
if (resamplefd && !IS_ERR(resamplefd))
417+
eventfd_ctx_put(resamplefd);
418+
279419
if (eventfd && !IS_ERR(eventfd))
280420
eventfd_ctx_put(eventfd);
281421

@@ -291,6 +431,8 @@ kvm_eventfd_init(struct kvm *kvm)
291431
{
292432
spin_lock_init(&kvm->irqfds.lock);
293433
INIT_LIST_HEAD(&kvm->irqfds.items);
434+
INIT_LIST_HEAD(&kvm->irqfds.resampler_list);
435+
mutex_init(&kvm->irqfds.resampler_lock);
294436
INIT_LIST_HEAD(&kvm->ioeventfds);
295437
}
296438

@@ -340,7 +482,7 @@ kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
340482
int
341483
kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
342484
{
343-
if (args->flags & ~KVM_IRQFD_FLAG_DEASSIGN)
485+
if (args->flags & ~(KVM_IRQFD_FLAG_DEASSIGN | KVM_IRQFD_FLAG_RESAMPLE))
344486
return -EINVAL;
345487

346488
if (args->flags & KVM_IRQFD_FLAG_DEASSIGN)

‎virt/kvm/irq_comm.c

+6
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ int kvm_request_irq_source_id(struct kvm *kvm)
228228
}
229229

230230
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
231+
#ifdef CONFIG_X86
232+
ASSERT(irq_source_id != KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID);
233+
#endif
231234
set_bit(irq_source_id, bitmap);
232235
unlock:
233236
mutex_unlock(&kvm->irq_lock);
@@ -238,6 +241,9 @@ int kvm_request_irq_source_id(struct kvm *kvm)
238241
void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
239242
{
240243
ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID);
244+
#ifdef CONFIG_X86
245+
ASSERT(irq_source_id != KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID);
246+
#endif
241247

242248
mutex_lock(&kvm->irq_lock);
243249
if (irq_source_id < 0 ||

0 commit comments

Comments
 (0)
Please sign in to comment.