[PATCH 17/17] mshv: Use in kernel MSI routing for irqfd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Use the in-kernel routing information for irqfd interrupts.

Signed-off-by: Vineeth Pillai <viremana@xxxxxxxxxxxxxxxxxxx>
---
 drivers/hv/hv_eventfd.c      | 94 +++++++++++++++++++++++++++---------
 drivers/hv/mshv_msi.c        |  1 +
 include/linux/mshv.h         |  2 +
 include/linux/mshv_eventfd.h | 26 +++++-----
 include/uapi/linux/mshv.h    |  6 ---
 5 files changed, 87 insertions(+), 42 deletions(-)

diff --git a/drivers/hv/hv_eventfd.c b/drivers/hv/hv_eventfd.c
index 6404624b3bc6..729b5f67aa9a 100644
--- a/drivers/hv/hv_eventfd.c
+++ b/drivers/hv/hv_eventfd.c
@@ -88,13 +88,32 @@ irqfd_resampler_ack(struct mshv_irq_ack_notifier *mian)
 static void
 irqfd_inject(struct mshv_kernel_irqfd *irqfd)
 {
+	struct mshv_partition *partition = irqfd->partition;
 	struct mshv_lapic_irq *irq = &irqfd->lapic_irq;
+	unsigned int seq;
+	int idx;
 
 	WARN_ON(irqfd->resampler &&
 		!irq->control.level_triggered);
+
+	idx = srcu_read_lock(&partition->irq_srcu);
+	if (irqfd->msi_entry.gsi) {
+		if (!irqfd->msi_entry.entry_valid) {
+			pr_warn("Invalid routing info for gsi %u",
+				irqfd->msi_entry.gsi);
+			srcu_read_unlock(&partition->irq_srcu, idx);
+			return;
+		}
+
+		do {
+			seq = read_seqcount_begin(&irqfd->msi_entry_sc);
+		} while (read_seqcount_retry(&irqfd->msi_entry_sc, seq));
+	}
+
 	hv_call_assert_virtual_interrupt(irqfd->partition->id,
 					 irq->vector, irq->apic_id,
 					 irq->control);
+	srcu_read_unlock(&partition->irq_srcu, idx);
 }
 
 static void
@@ -206,6 +225,27 @@ irqfd_wakeup(wait_queue_entry_t *wait, unsigned int mode,
 	return 0;
 }
 
+/* Must be called under irqfds.lock */
+static void irqfd_update(struct mshv_partition *partition,
+			 struct mshv_kernel_irqfd *irqfd)
+{
+	write_seqcount_begin(&irqfd->msi_entry_sc);
+	irqfd->msi_entry = mshv_msi_map_gsi(partition, irqfd->gsi);
+	mshv_set_msi_irq(&irqfd->msi_entry, &irqfd->lapic_irq);
+	write_seqcount_end(&irqfd->msi_entry_sc);
+}
+
+void mshv_irqfd_routing_update(struct mshv_partition *partition)
+{
+	struct mshv_kernel_irqfd *irqfd;
+
+	spin_lock_irq(&partition->irqfds.lock);
+	list_for_each_entry(irqfd, &partition->irqfds.items, list) {
+		irqfd_update(partition, irqfd);
+	}
+	spin_unlock_irq(&partition->irqfds.lock);
+}
+
 static void
 irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh,
 			poll_table *pt)
@@ -221,29 +261,23 @@ static int
 mshv_irqfd_assign(struct mshv_partition *partition,
 		  struct mshv_irqfd *args)
 {
+	struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
 	struct mshv_kernel_irqfd *irqfd, *tmp;
+	unsigned int events;
 	struct fd f;
-	struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
 	int ret;
-	unsigned int events;
+	int idx;
 
 	irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL);
 	if (!irqfd)
 		return -ENOMEM;
 
-	if (args->flags & MSHV_IRQFD_FLAG_RESAMPLE &&
-		!args->level_triggered)
-		return -EINVAL;
-
 	irqfd->partition = partition;
 	irqfd->gsi = args->gsi;
-	irqfd->lapic_irq.vector = args->vector;
-	irqfd->lapic_irq.apic_id = args->apic_id;
-	irqfd->lapic_irq.control.interrupt_type = args->interrupt_type;
-	irqfd->lapic_irq.control.level_triggered = args->level_triggered;
-	irqfd->lapic_irq.control.logical_dest_mode = args->logical_dest_mode;
 	INIT_LIST_HEAD(&irqfd->list);
 	INIT_WORK(&irqfd->shutdown, irqfd_shutdown);
+	seqcount_spinlock_init(&irqfd->msi_entry_sc,
+			       &partition->irqfds.lock);
 
 	f = fdget(args->fd);
 	if (!f.file) {
@@ -259,6 +293,31 @@ mshv_irqfd_assign(struct mshv_partition *partition,
 
 	irqfd->eventfd = eventfd;
 
+
+	spin_lock_irq(&partition->irqfds.lock);
+	idx = srcu_read_lock(&partition->irq_srcu);
+	irqfd_update(partition, irqfd);
+	srcu_read_unlock(&partition->irq_srcu, idx);
+
+	if (args->flags & MSHV_IRQFD_FLAG_RESAMPLE &&
+	    !irqfd->lapic_irq.control.level_triggered) {
+		spin_unlock_irq(&partition->irqfds.lock);
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	ret = 0;
+	list_for_each_entry(tmp, &partition->irqfds.items, list) {
+		if (irqfd->eventfd != tmp->eventfd)
+			continue;
+		/* This fd is used for another irq already. */
+		ret = -EBUSY;
+		spin_unlock_irq(&partition->irqfds.lock);
+		goto fail;
+	}
+	list_add_tail(&irqfd->list, &partition->irqfds.items);
+	spin_unlock_irq(&partition->irqfds.lock);
+
 	if (args->flags & MSHV_IRQFD_FLAG_RESAMPLE) {
 		struct mshv_kernel_irqfd_resampler *resampler;
 
@@ -314,19 +373,6 @@ mshv_irqfd_assign(struct mshv_partition *partition,
 	init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
 	init_poll_funcptr(&irqfd->pt, irqfd_ptable_queue_proc);
 
-	spin_lock_irq(&partition->irqfds.lock);
-	ret = 0;
-	list_for_each_entry(tmp, &partition->irqfds.items, list) {
-		if (irqfd->eventfd != tmp->eventfd)
-			continue;
-		/* This fd is used for another irq already. */
-		ret = -EBUSY;
-		spin_unlock_irq(&partition->irqfds.lock);
-		goto fail;
-	}
-	list_add_tail(&irqfd->list, &partition->irqfds.items);
-	spin_unlock_irq(&partition->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.
diff --git a/drivers/hv/mshv_msi.c b/drivers/hv/mshv_msi.c
index ae25ed8dfef4..c5dc9c6fe4d5 100644
--- a/drivers/hv/mshv_msi.c
+++ b/drivers/hv/mshv_msi.c
@@ -71,6 +71,7 @@ int mshv_set_msi_routing(struct mshv_partition *partition,
 	spin_lock(&partition->irq_lock);
 	old = rcu_dereference_protected(partition->msi_routing, 1);
 	rcu_assign_pointer(partition->msi_routing, new);
+	mshv_irqfd_routing_update(partition);
 	spin_unlock(&partition->irq_lock);
 
 	synchronize_srcu_expedited(&partition->irq_srcu);
diff --git a/include/linux/mshv.h b/include/linux/mshv.h
index ec349be0ba91..fc655b60c5cd 100644
--- a/include/linux/mshv.h
+++ b/include/linux/mshv.h
@@ -104,6 +104,8 @@ struct mshv_kernel_msi_routing_entry mshv_msi_map_gsi(
 void mshv_set_msi_irq(struct mshv_kernel_msi_routing_entry *e,
 		      struct mshv_lapic_irq *irq);
 
+void mshv_irqfd_routing_update(struct mshv_partition *partition);
+
 struct hv_synic_pages {
 	struct hv_message_page *synic_message_page;
 	struct hv_synic_event_flags_page *synic_event_flags_page;
diff --git a/include/linux/mshv_eventfd.h b/include/linux/mshv_eventfd.h
index fa5d46d2eb85..a24ca167f3e9 100644
--- a/include/linux/mshv_eventfd.h
+++ b/include/linux/mshv_eventfd.h
@@ -39,20 +39,22 @@ struct mshv_kernel_irqfd_resampler {
 };
 
 struct mshv_kernel_irqfd {
-	struct mshv_partition     *partition;
-	struct eventfd_ctx        *eventfd;
-	u32                        gsi;
-	struct mshv_lapic_irq      lapic_irq;
-	struct list_head           list;
-	poll_table                 pt;
-	wait_queue_head_t         *wqh;
-	wait_queue_entry_t         wait;
-	struct work_struct         shutdown;
+	struct mshv_partition                *partition;
+	struct eventfd_ctx                   *eventfd;
+	struct mshv_kernel_msi_routing_entry msi_entry;
+	seqcount_spinlock_t                  msi_entry_sc;
+	u32                                  gsi;
+	struct mshv_lapic_irq                lapic_irq;
+	struct list_head                     list;
+	poll_table                           pt;
+	wait_queue_head_t                    *wqh;
+	wait_queue_entry_t                   wait;
+	struct work_struct                   shutdown;
 
 	/* Resampler related */
-	struct mshv_kernel_irqfd_resampler *resampler;
-	struct eventfd_ctx *resamplefd;
-	struct list_head resampler_link;
+	struct mshv_kernel_irqfd_resampler   *resampler;
+	struct eventfd_ctx                   *resamplefd;
+	struct list_head                     resampler_link;
 };
 
 int mshv_irqfd(struct mshv_partition *partition,
diff --git a/include/uapi/linux/mshv.h b/include/uapi/linux/mshv.h
index ac58f2ded79c..b5826120ba7c 100644
--- a/include/uapi/linux/mshv.h
+++ b/include/uapi/linux/mshv.h
@@ -83,16 +83,10 @@ struct mshv_translate_gva {
 #define MSHV_IRQFD_FLAG_RESAMPLE (1 << 1)
 
 struct mshv_irqfd {
-	__u64 apic_id;
 	__s32 fd;
 	__s32 resamplefd;
 	__u32 gsi;
-	__u32 vector;
-	__u32 interrupt_type;
 	__u32 flags;
-	__u8  level_triggered;
-	__u8  logical_dest_mode;
-	__u8  pad[6];
 };
 
 enum {
-- 
2.25.1




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux