Blob Blame History Raw
From: Olaf Hering <ohering@suse.de>
Subject: pci-hyperv: increase HV_VP_SET_BANK_COUNT_MAX to handle 1792 vcpus
Patch-mainline: never, upstream uses cpumask_to_vpset
References: fate#327171, bsc#1122822

Michael H. Kelley says:

vp_set.valid_banks is a bitmap, with one bit for each 64-bit word in the
'masks' array that is valid.  (I don't know why "mask" is named "masks".
It really should be named "banks".)  A zero bit in valid_banks indicates
a 64-bit word in 'masks' that is not even present.  So if bits 0 and 2
in valid_banks are set, then the 'masks' array would contain two 64 bit
words, representing CPUs 0-63 and CPUs 128-191. But the code simplifies
things a bit by never skipping a bit in valid_banks, even if the
corresponding 64-bit word in 'masks' is all zeros.

Finally, we can't set a bit in valid_banks for a CPU range that isn't
supported by the underlying Hyper-V, as Hyper-V will return an error
even if the corresponding entry in the 'masks' array is all zeros.  So
we can't just set all 28 low order bits in valid_banks, because older
versions of Hyper-V will return an error.

--- a/drivers/pci/host/pci-hyperv.c
+++ b/drivers/pci/host/pci-hyperv.c
@@ -397,12 +397,12 @@ struct hv_interrupt_entry {
 	u32	data;
 };
 
-#define HV_VP_SET_BANK_COUNT_MAX	5 /* current implementation limit */
+#define HV_VP_SET_BANK_COUNT_MAX	28 /* current implementation limit */
 
 struct hv_vp_set {
 	u64	format;			/* 0 (HvGenericSetSparse4k) */
 	u64	valid_banks;
-	u64	masks[HV_VP_SET_BANK_COUNT_MAX];
+	u64	banks[HV_VP_SET_BANK_COUNT_MAX];
 };
 
 /*
@@ -925,6 +925,7 @@ static void hv_irq_unmask(struct irq_dat
 	u32 var_size = 0;
 	int cpu_vmbus;
 	int cpu;
+	int index, maxindex = 0;
 	u64 res;
 
 	dest = irq_data_get_effective_affinity_mask(data);
@@ -964,14 +965,6 @@ static void hv_irq_unmask(struct irq_dat
 		 */
 		params->int_target.flags |=
 			HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET;
-		params->int_target.vp_set.valid_banks =
-			(1ull << HV_VP_SET_BANK_COUNT_MAX) - 1;
-
-		/*
-		 * var-sized hypercall, var-size starts after vp_mask (thus
-		 * vp_set.format does not count, but vp_set.valid_banks does).
-		 */
-		var_size = 1 + HV_VP_SET_BANK_COUNT_MAX;
 
 		for_each_cpu_and(cpu, dest, cpu_online_mask) {
 			cpu_vmbus = hv_cpu_number_to_vp_number(cpu);
@@ -983,9 +976,18 @@ static void hv_irq_unmask(struct irq_dat
 				goto exit_unlock;
 			}
 
-			params->int_target.vp_set.masks[cpu_vmbus / 64] |=
+			index = cpu_vmbus / 64;
+			if (index > maxindex)
+				maxindex = index;
+			params->int_target.vp_set.banks[index] |=
 				(1ULL << (cpu_vmbus & 63));
 		}
+		/*
+		 * var-sized hypercall, var-size starts after vp_mask (thus
+		 * vp_set.format does not count, but vp_set.valid_banks does).
+		 */
+		var_size = 1 + maxindex + 1;
+		params->int_target.vp_set.valid_banks = (1ULL << (maxindex + 1)) - 1;
 	} else {
 		for_each_cpu_and(cpu, dest, cpu_online_mask) {
 			params->int_target.vp_mask |=