ANDROID: virt: geniezone: Refactoring irqfd to align with upstream v6
[Detail] - remove register/unregister ack notifier - remove spi setting - remove resamplerfd - remove resampler_link Change-Id: I7c641ba16ebcba208592dc78337501014a832ddf Signed-off-by: Yingshiuan Pan <yingshiuan.pan@mediatek.com> Signed-off-by: Yi-De Wu <yi-de.wu@mediatek.com> Bug: 301179926 Link: https://lore.kernel.org/all/20230919111210.19615-10-yi-de.wu@mediatek.com/
This commit is contained in:
parent
7e1cb3bdec
commit
fb3444af07
@ -14,41 +14,11 @@ struct gzvm_irq_ack_notifier {
|
||||
void (*irq_acked)(struct gzvm_irq_ack_notifier *ian);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gzvm_kernel_irqfd_resampler - irqfd resampler descriptor.
|
||||
* @gzvm: Poiner to gzvm.
|
||||
* @list: List of resampling struct _irqfd objects sharing this gsi.
|
||||
* RCU list modified under gzvm->irqfds.resampler_lock.
|
||||
* @notifier: gzvm irq ack notifier.
|
||||
* @link: Entry in list of gzvm->irqfd.resampler_list.
|
||||
* Use for sharing esamplers among irqfds on the same gsi.
|
||||
* Accessed and modified under gzvm->irqfds.resampler_lock.
|
||||
*
|
||||
* Resampling irqfds are a special variety of irqfds used to emulate
|
||||
* level triggered interrupts. The interrupt is asserted on eventfd
|
||||
* trigger. On acknowledgment through the irq ack notifier, the
|
||||
* interrupt is de-asserted and userspace is notified through the
|
||||
* resamplefd. All resamplers on the same gsi are de-asserted
|
||||
* together, so we don't need to track the state of each individual
|
||||
* user. We can also therefore share the same irq source ID.
|
||||
*/
|
||||
struct gzvm_kernel_irqfd_resampler {
|
||||
struct gzvm *gzvm;
|
||||
|
||||
struct list_head list;
|
||||
struct gzvm_irq_ack_notifier notifier;
|
||||
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct gzvm_kernel_irqfd: gzvm kernel irqfd descriptor.
|
||||
* @gzvm: Pointer to struct gzvm.
|
||||
* @wait: Wait queue entry.
|
||||
* @gsi: Used for level IRQ fast-path.
|
||||
* @resampler: The resampler used by this irqfd (resampler-only).
|
||||
* @resamplefd: Eventfd notified on resample (resampler-only).
|
||||
* @resampler_link: Entry in list of irqfds for a resampler (resampler-only).
|
||||
* @eventfd: Used for setup/shutdown.
|
||||
* @list: struct list_head.
|
||||
* @pt: struct poll_table_struct.
|
||||
@ -60,12 +30,6 @@ struct gzvm_kernel_irqfd {
|
||||
|
||||
int gsi;
|
||||
|
||||
struct gzvm_kernel_irqfd_resampler *resampler;
|
||||
|
||||
struct eventfd_ctx *resamplefd;
|
||||
|
||||
struct list_head resampler_link;
|
||||
|
||||
struct eventfd_ctx *eventfd;
|
||||
struct list_head list;
|
||||
poll_table pt;
|
||||
@ -89,77 +53,6 @@ static void irqfd_set_spi(struct gzvm *gzvm, int irq_source_id, u32 irq,
|
||||
gzvm_irqchip_inject_irq(gzvm, irq_source_id, 0, irq, level);
|
||||
}
|
||||
|
||||
/**
|
||||
* irqfd_resampler_ack() - Notify all of the resampler irqfds using this GSI
|
||||
* when IRQ de-assert once.
|
||||
* @ian: Pointer to gzvm_irq_ack_notifier.
|
||||
*
|
||||
* Since resampler irqfds share an IRQ source ID, we de-assert once
|
||||
* then notify all of the resampler irqfds using this GSI. We can't
|
||||
* do multiple de-asserts or we risk racing with incoming re-asserts.
|
||||
*/
|
||||
static void irqfd_resampler_ack(struct gzvm_irq_ack_notifier *ian)
|
||||
{
|
||||
struct gzvm_kernel_irqfd_resampler *resampler;
|
||||
struct gzvm *gzvm;
|
||||
struct gzvm_kernel_irqfd *irqfd;
|
||||
int idx;
|
||||
|
||||
resampler = container_of(ian,
|
||||
struct gzvm_kernel_irqfd_resampler, notifier);
|
||||
gzvm = resampler->gzvm;
|
||||
|
||||
irqfd_set_spi(gzvm, GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
|
||||
resampler->notifier.gsi, 0, false);
|
||||
|
||||
idx = srcu_read_lock(&gzvm->irq_srcu);
|
||||
|
||||
list_for_each_entry_srcu(irqfd, &resampler->list, resampler_link,
|
||||
srcu_read_lock_held(&gzvm->irq_srcu)) {
|
||||
eventfd_signal(irqfd->resamplefd, 1);
|
||||
}
|
||||
|
||||
srcu_read_unlock(&gzvm->irq_srcu, idx);
|
||||
}
|
||||
|
||||
static void gzvm_register_irq_ack_notifier(struct gzvm *gzvm,
|
||||
struct gzvm_irq_ack_notifier *ian)
|
||||
{
|
||||
mutex_lock(&gzvm->irq_lock);
|
||||
hlist_add_head_rcu(&ian->link, &gzvm->irq_ack_notifier_list);
|
||||
mutex_unlock(&gzvm->irq_lock);
|
||||
}
|
||||
|
||||
static void gzvm_unregister_irq_ack_notifier(struct gzvm *gzvm,
|
||||
struct gzvm_irq_ack_notifier *ian)
|
||||
{
|
||||
mutex_lock(&gzvm->irq_lock);
|
||||
hlist_del_init_rcu(&ian->link);
|
||||
mutex_unlock(&gzvm->irq_lock);
|
||||
synchronize_srcu(&gzvm->irq_srcu);
|
||||
}
|
||||
|
||||
static void irqfd_resampler_shutdown(struct gzvm_kernel_irqfd *irqfd)
|
||||
{
|
||||
struct gzvm_kernel_irqfd_resampler *resampler = irqfd->resampler;
|
||||
struct gzvm *gzvm = resampler->gzvm;
|
||||
|
||||
mutex_lock(&gzvm->irqfds.resampler_lock);
|
||||
|
||||
list_del_rcu(&irqfd->resampler_link);
|
||||
synchronize_srcu(&gzvm->irq_srcu);
|
||||
|
||||
if (list_empty(&resampler->list)) {
|
||||
list_del(&resampler->link);
|
||||
gzvm_unregister_irq_ack_notifier(gzvm, &resampler->notifier);
|
||||
irqfd_set_spi(gzvm, GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
|
||||
resampler->notifier.gsi, 0, false);
|
||||
kfree(resampler);
|
||||
}
|
||||
|
||||
mutex_unlock(&gzvm->irqfds.resampler_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* irqfd_shutdown() - Race-free decouple logic (ordering is critical).
|
||||
* @work: Pointer to work_struct.
|
||||
@ -180,11 +73,6 @@ static void irqfd_shutdown(struct work_struct *work)
|
||||
*/
|
||||
eventfd_ctx_remove_wait_queue(irqfd->eventfd, &irqfd->wait, &cnt);
|
||||
|
||||
if (irqfd->resampler) {
|
||||
irqfd_resampler_shutdown(irqfd);
|
||||
eventfd_ctx_put(irqfd->resamplefd);
|
||||
}
|
||||
|
||||
/*
|
||||
* It is now safe to release the object's resources
|
||||
*/
|
||||
@ -278,9 +166,8 @@ static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
|
||||
{
|
||||
struct gzvm_kernel_irqfd *irqfd, *tmp;
|
||||
struct fd f;
|
||||
struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
|
||||
struct eventfd_ctx *eventfd = NULL;
|
||||
int ret;
|
||||
__poll_t events;
|
||||
int idx;
|
||||
|
||||
irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL_ACCOUNT);
|
||||
@ -289,7 +176,6 @@ static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
|
||||
|
||||
irqfd->gzvm = gzvm;
|
||||
irqfd->gsi = args->gsi;
|
||||
irqfd->resampler = NULL;
|
||||
|
||||
INIT_LIST_HEAD(&irqfd->list);
|
||||
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
|
||||
@ -308,55 +194,6 @@ static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
|
||||
|
||||
irqfd->eventfd = eventfd;
|
||||
|
||||
if (args->flags & GZVM_IRQFD_FLAG_RESAMPLE) {
|
||||
struct gzvm_kernel_irqfd_resampler *resampler;
|
||||
|
||||
resamplefd = eventfd_ctx_fdget(args->resamplefd);
|
||||
if (IS_ERR(resamplefd)) {
|
||||
ret = PTR_ERR(resamplefd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
irqfd->resamplefd = resamplefd;
|
||||
INIT_LIST_HEAD(&irqfd->resampler_link);
|
||||
|
||||
mutex_lock(&gzvm->irqfds.resampler_lock);
|
||||
|
||||
list_for_each_entry(resampler,
|
||||
&gzvm->irqfds.resampler_list, link) {
|
||||
if (resampler->notifier.gsi == irqfd->gsi) {
|
||||
irqfd->resampler = resampler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!irqfd->resampler) {
|
||||
resampler = kzalloc(sizeof(*resampler),
|
||||
GFP_KERNEL_ACCOUNT);
|
||||
if (!resampler) {
|
||||
ret = -ENOMEM;
|
||||
mutex_unlock(&gzvm->irqfds.resampler_lock);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
resampler->gzvm = gzvm;
|
||||
INIT_LIST_HEAD(&resampler->list);
|
||||
resampler->notifier.gsi = irqfd->gsi;
|
||||
resampler->notifier.irq_acked = irqfd_resampler_ack;
|
||||
INIT_LIST_HEAD(&resampler->link);
|
||||
|
||||
list_add(&resampler->link, &gzvm->irqfds.resampler_list);
|
||||
gzvm_register_irq_ack_notifier(gzvm,
|
||||
&resampler->notifier);
|
||||
irqfd->resampler = resampler;
|
||||
}
|
||||
|
||||
list_add_rcu(&irqfd->resampler_link, &irqfd->resampler->list);
|
||||
synchronize_srcu(&gzvm->irq_srcu);
|
||||
|
||||
mutex_unlock(&gzvm->irqfds.resampler_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install our own custom wake-up handling so we are notified via
|
||||
* a callback whenever someone signals the underlying eventfd
|
||||
@ -383,16 +220,7 @@ static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
|
||||
|
||||
spin_unlock_irq(&gzvm->irqfds.lock);
|
||||
|
||||
/*
|
||||
* Check if there was an event already pending on the eventfd
|
||||
* before we registered, and trigger it as if we didn't miss it.
|
||||
*/
|
||||
events = vfs_poll(f.file, &irqfd->pt);
|
||||
|
||||
/* In case there is already a pending event */
|
||||
if (events & EPOLLIN)
|
||||
irqfd_set_spi(gzvm, GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
|
||||
irqfd->gsi, 1, false);
|
||||
vfs_poll(f.file, &irqfd->pt);
|
||||
|
||||
srcu_read_unlock(&gzvm->irq_srcu, idx);
|
||||
|
||||
@ -404,12 +232,6 @@ static int gzvm_irqfd_assign(struct gzvm *gzvm, struct gzvm_irqfd *args)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (irqfd->resampler)
|
||||
irqfd_resampler_shutdown(irqfd);
|
||||
|
||||
if (resamplefd && !IS_ERR(resamplefd))
|
||||
eventfd_ctx_put(resamplefd);
|
||||
|
||||
if (eventfd && !IS_ERR(eventfd))
|
||||
eventfd_ctx_put(eventfd);
|
||||
|
||||
@ -509,11 +331,9 @@ int gzvm_vm_irqfd_init(struct gzvm *gzvm)
|
||||
|
||||
spin_lock_init(&gzvm->irqfds.lock);
|
||||
INIT_LIST_HEAD(&gzvm->irqfds.items);
|
||||
INIT_LIST_HEAD(&gzvm->irqfds.resampler_list);
|
||||
if (init_srcu_struct(&gzvm->irq_srcu))
|
||||
return -EINVAL;
|
||||
INIT_HLIST_HEAD(&gzvm->irq_ack_notifier_list);
|
||||
mutex_init(&gzvm->irqfds.resampler_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user