mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
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:
@@ -14,41 +14,11 @@ struct gzvm_irq_ack_notifier {
|
|||||||
void (*irq_acked)(struct gzvm_irq_ack_notifier *ian);
|
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.
|
* struct gzvm_kernel_irqfd: gzvm kernel irqfd descriptor.
|
||||||
* @gzvm: Pointer to struct gzvm.
|
* @gzvm: Pointer to struct gzvm.
|
||||||
* @wait: Wait queue entry.
|
* @wait: Wait queue entry.
|
||||||
* @gsi: Used for level IRQ fast-path.
|
* @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.
|
* @eventfd: Used for setup/shutdown.
|
||||||
* @list: struct list_head.
|
* @list: struct list_head.
|
||||||
* @pt: struct poll_table_struct.
|
* @pt: struct poll_table_struct.
|
||||||
@@ -60,12 +30,6 @@ struct gzvm_kernel_irqfd {
|
|||||||
|
|
||||||
int gsi;
|
int gsi;
|
||||||
|
|
||||||
struct gzvm_kernel_irqfd_resampler *resampler;
|
|
||||||
|
|
||||||
struct eventfd_ctx *resamplefd;
|
|
||||||
|
|
||||||
struct list_head resampler_link;
|
|
||||||
|
|
||||||
struct eventfd_ctx *eventfd;
|
struct eventfd_ctx *eventfd;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
poll_table pt;
|
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);
|
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).
|
* irqfd_shutdown() - Race-free decouple logic (ordering is critical).
|
||||||
* @work: Pointer to work_struct.
|
* @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);
|
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
|
* 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 gzvm_kernel_irqfd *irqfd, *tmp;
|
||||||
struct fd f;
|
struct fd f;
|
||||||
struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
|
struct eventfd_ctx *eventfd = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
__poll_t events;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL_ACCOUNT);
|
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->gzvm = gzvm;
|
||||||
irqfd->gsi = args->gsi;
|
irqfd->gsi = args->gsi;
|
||||||
irqfd->resampler = NULL;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&irqfd->list);
|
INIT_LIST_HEAD(&irqfd->list);
|
||||||
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
|
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;
|
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
|
* Install our own custom wake-up handling so we are notified via
|
||||||
* a callback whenever someone signals the underlying eventfd
|
* 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);
|
spin_unlock_irq(&gzvm->irqfds.lock);
|
||||||
|
|
||||||
/*
|
vfs_poll(f.file, &irqfd->pt);
|
||||||
* 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);
|
|
||||||
|
|
||||||
srcu_read_unlock(&gzvm->irq_srcu, idx);
|
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;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (irqfd->resampler)
|
|
||||||
irqfd_resampler_shutdown(irqfd);
|
|
||||||
|
|
||||||
if (resamplefd && !IS_ERR(resamplefd))
|
|
||||||
eventfd_ctx_put(resamplefd);
|
|
||||||
|
|
||||||
if (eventfd && !IS_ERR(eventfd))
|
if (eventfd && !IS_ERR(eventfd))
|
||||||
eventfd_ctx_put(eventfd);
|
eventfd_ctx_put(eventfd);
|
||||||
|
|
||||||
@@ -509,11 +331,9 @@ int gzvm_vm_irqfd_init(struct gzvm *gzvm)
|
|||||||
|
|
||||||
spin_lock_init(&gzvm->irqfds.lock);
|
spin_lock_init(&gzvm->irqfds.lock);
|
||||||
INIT_LIST_HEAD(&gzvm->irqfds.items);
|
INIT_LIST_HEAD(&gzvm->irqfds.items);
|
||||||
INIT_LIST_HEAD(&gzvm->irqfds.resampler_list);
|
|
||||||
if (init_srcu_struct(&gzvm->irq_srcu))
|
if (init_srcu_struct(&gzvm->irq_srcu))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
INIT_HLIST_HEAD(&gzvm->irq_ack_notifier_list);
|
INIT_HLIST_HEAD(&gzvm->irq_ack_notifier_list);
|
||||||
mutex_init(&gzvm->irqfds.resampler_lock);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user