Unverified Commit 86a5f2d8 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files
parents 7ecad26d 5d5f5a1d
Loading
Loading
Loading
Loading
+43 −41
Original line number Diff line number Diff line
@@ -82,20 +82,10 @@ const struct evtchn_ops *evtchn_ops;
 */
static DEFINE_MUTEX(irq_mapping_update_lock);

/*
 * Lock protecting event handling loop against removing event channels.
 * Adding of event channels is no issue as the associated IRQ becomes active
 * only after everything is setup (before request_[threaded_]irq() the handler
 * can't be entered for an event, as the event channel will be unmasked only
 * then).
 */
static DEFINE_RWLOCK(evtchn_rwlock);

/*
 * Lock hierarchy:
 *
 * irq_mapping_update_lock
 *   evtchn_rwlock
 *   IRQ-desc lock
 *     percpu eoi_list_lock
 */
@@ -191,6 +181,22 @@ struct irq_info *info_for_irq(unsigned irq)
	return irq_get_handler_data(irq);
}

static void delayed_free_irq(struct work_struct *work)
{
	struct irq_info *info = container_of(to_rcu_work(work), struct irq_info,
					     rwork);
	unsigned int irq = info->irq;

	/* Remove the info pointer only now, with no potential users left. */
	irq_set_handler_data(irq, NULL);

	kfree(info);

	/* Legacy IRQ descriptors are managed by the arch. */
	if (irq >= nr_legacy_irqs())
		irq_free_desc(irq);
}

/* Constructors for packed IRQ information. */
static int xen_irq_info_common_setup(struct irq_info *info,
				     unsigned irq,
@@ -474,33 +480,36 @@ static void xen_irq_lateeoi_worker(struct work_struct *work)

	eoi = container_of(to_delayed_work(work), struct lateeoi_work, delayed);

	read_lock_irqsave(&evtchn_rwlock, flags);
	rcu_read_lock();

	while (true) {
		spin_lock(&eoi->eoi_list_lock);
		spin_lock_irqsave(&eoi->eoi_list_lock, flags);

		info = list_first_entry_or_null(&eoi->eoi_list, struct irq_info,
						eoi_list);

		if (info == NULL || now < info->eoi_time) {
			spin_unlock(&eoi->eoi_list_lock);
		if (info == NULL)
			break;

		if (now < info->eoi_time) {
			mod_delayed_work_on(info->eoi_cpu, system_wq,
					    &eoi->delayed,
					    info->eoi_time - now);
			break;
		}

		list_del_init(&info->eoi_list);

		spin_unlock(&eoi->eoi_list_lock);
		spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);

		info->eoi_time = 0;

		xen_irq_lateeoi_locked(info);
	}

	if (info)
		mod_delayed_work_on(info->eoi_cpu, system_wq,
				    &eoi->delayed, info->eoi_time - now);
	spin_unlock_irqrestore(&eoi->eoi_list_lock, flags);

	read_unlock_irqrestore(&evtchn_rwlock, flags);
	rcu_read_unlock();
}

static void xen_cpu_init_eoi(unsigned int cpu)
@@ -515,16 +524,15 @@ static void xen_cpu_init_eoi(unsigned int cpu)
void xen_irq_lateeoi(unsigned int irq, unsigned int eoi_flags)
{
	struct irq_info *info;
	unsigned long flags;

	read_lock_irqsave(&evtchn_rwlock, flags);
	rcu_read_lock();

	info = info_for_irq(irq);

	if (info)
		xen_irq_lateeoi_locked(info);

	read_unlock_irqrestore(&evtchn_rwlock, flags);
	rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(xen_irq_lateeoi);

@@ -543,6 +551,7 @@ static void xen_irq_init(unsigned irq)

	info->type = IRQT_UNBOUND;
	info->refcnt = -1;
	INIT_RCU_WORK(&info->rwork, delayed_free_irq);

	irq_set_handler_data(irq, info);

@@ -595,31 +604,18 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
static void xen_free_irq(unsigned irq)
{
	struct irq_info *info = irq_get_handler_data(irq);
	unsigned long flags;

	if (WARN_ON(!info))
		return;

	write_lock_irqsave(&evtchn_rwlock, flags);

	if (!list_empty(&info->eoi_list))
		lateeoi_list_del(info);

	list_del(&info->list);

	irq_set_handler_data(irq, NULL);

	WARN_ON(info->refcnt > 0);

	write_unlock_irqrestore(&evtchn_rwlock, flags);

	kfree(info);

	/* Legacy IRQ descriptors are managed by the arch. */
	if (irq < nr_legacy_irqs())
		return;

	irq_free_desc(irq);
	queue_rcu_work(system_wq, &info->rwork);
}

static void xen_evtchn_close(unsigned int port)
@@ -1521,7 +1517,14 @@ static void __xen_evtchn_do_upcall(void)
	struct evtchn_loop_ctrl ctrl = { 0 };
	unsigned count;

	read_lock(&evtchn_rwlock);
	/*
	 * When closing an event channel the associated IRQ must not be freed
	 * until all cpus have left the event handling loop. This is ensured
	 * by taking the rcu_read_lock() while handling events, as freeing of
	 * the IRQ is handled via queue_rcu_work() _after_ closing the event
	 * channel.
	 */
	rcu_read_lock();

	do {
		vcpu_info->evtchn_upcall_pending = 0;
@@ -1538,8 +1541,7 @@ static void __xen_evtchn_do_upcall(void)
	} while (count != 1 || vcpu_info->evtchn_upcall_pending);

out:

	read_unlock(&evtchn_rwlock);
	rcu_read_unlock();

	/*
	 * Increment irq_epoch only now to defer EOIs only for
+2 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 */
#ifndef __EVENTS_INTERNAL_H__
#define __EVENTS_INTERNAL_H__
#include <linux/rcupdate.h>

/* Interrupt types. */
enum xen_irq_type {
@@ -33,6 +34,7 @@ enum xen_irq_type {
struct irq_info {
	struct list_head list;
	struct list_head eoi_list;
	struct rcu_work rwork;
	int refcnt;
	enum xen_irq_type type;	/* type */
	unsigned irq;