diff options
-rw-r--r-- | drivers/pci/controller/pci-hyperv.c | 67 |
1 files changed, 62 insertions, 5 deletions
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c index a53bd8728d0d..c1575a5d0352 100644 --- a/drivers/pci/controller/pci-hyperv.c +++ b/drivers/pci/controller/pci-hyperv.c @@ -64,6 +64,7 @@ enum pci_protocol_version_t { PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1), /* Win10 */ PCI_PROTOCOL_VERSION_1_2 = PCI_MAKE_VERSION(1, 2), /* RS1 */ PCI_PROTOCOL_VERSION_1_3 = PCI_MAKE_VERSION(1, 3), /* Vibranium */ + PCI_PROTOCOL_VERSION_1_4 = PCI_MAKE_VERSION(1, 4), /* WS2022 */ }; #define CPU_AFFINITY_ALL -1ULL @@ -73,6 +74,7 @@ enum pci_protocol_version_t { * first. */ static enum pci_protocol_version_t pci_protocol_versions[] = { + PCI_PROTOCOL_VERSION_1_4, PCI_PROTOCOL_VERSION_1_3, PCI_PROTOCOL_VERSION_1_2, PCI_PROTOCOL_VERSION_1_1, @@ -122,6 +124,8 @@ enum pci_message_type { PCI_CREATE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x17, PCI_DELETE_INTERRUPT_MESSAGE2 = PCI_MESSAGE_BASE + 0x18, /* unused */ PCI_BUS_RELATIONS2 = PCI_MESSAGE_BASE + 0x19, + PCI_RESOURCES_ASSIGNED3 = PCI_MESSAGE_BASE + 0x1A, + PCI_CREATE_INTERRUPT_MESSAGE3 = PCI_MESSAGE_BASE + 0x1B, PCI_MESSAGE_MAXIMUM }; @@ -235,6 +239,21 @@ struct hv_msi_desc2 { u16 processor_array[32]; } __packed; +/* + * struct hv_msi_desc3 - 1.3 version of hv_msi_desc + * Everything is the same as in 'hv_msi_desc2' except that the size of the + * 'vector' field is larger to support bigger vector values. For ex: LPI + * vectors on ARM. + */ +struct hv_msi_desc3 { + u32 vector; + u8 delivery_mode; + u8 reserved; + u16 vector_count; + u16 processor_count; + u16 processor_array[32]; +} __packed; + /** * struct tran_int_desc * @reserved: unused, padding @@ -383,6 +402,12 @@ struct pci_create_interrupt2 { struct hv_msi_desc2 int_desc; } __packed; +struct pci_create_interrupt3 { + struct pci_message message_type; + union win_slot_encoding wslot; + struct hv_msi_desc3 int_desc; +} __packed; + struct pci_delete_interrupt { struct pci_message message_type; union win_slot_encoding wslot; @@ -1328,6 +1353,15 @@ static u32 hv_compose_msi_req_v1( return sizeof(*int_pkt); } +/* + * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten + * by subsequent retarget in hv_irq_unmask(). + */ +static int hv_compose_msi_req_get_cpu(struct cpumask *affinity) +{ + return cpumask_first_and(affinity, cpu_online_mask); +} + static u32 hv_compose_msi_req_v2( struct pci_create_interrupt2 *int_pkt, struct cpumask *affinity, u32 slot, u8 vector) @@ -1339,12 +1373,27 @@ static u32 hv_compose_msi_req_v2( int_pkt->int_desc.vector = vector; int_pkt->int_desc.vector_count = 1; int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED; + cpu = hv_compose_msi_req_get_cpu(affinity); + int_pkt->int_desc.processor_array[0] = + hv_cpu_number_to_vp_number(cpu); + int_pkt->int_desc.processor_count = 1; - /* - * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten - * by subsequent retarget in hv_irq_unmask(). - */ - cpu = cpumask_first_and(affinity, cpu_online_mask); + return sizeof(*int_pkt); +} + +static u32 hv_compose_msi_req_v3( + struct pci_create_interrupt3 *int_pkt, struct cpumask *affinity, + u32 slot, u32 vector) +{ + int cpu; + + int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE3; + int_pkt->wslot.slot = slot; + int_pkt->int_desc.vector = vector; + int_pkt->int_desc.reserved = 0; + int_pkt->int_desc.vector_count = 1; + int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED; + cpu = hv_compose_msi_req_get_cpu(affinity); int_pkt->int_desc.processor_array[0] = hv_cpu_number_to_vp_number(cpu); int_pkt->int_desc.processor_count = 1; @@ -1379,6 +1428,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) union { struct pci_create_interrupt v1; struct pci_create_interrupt2 v2; + struct pci_create_interrupt3 v3; } int_pkts; } __packed ctxt; @@ -1426,6 +1476,13 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) cfg->vector); break; + case PCI_PROTOCOL_VERSION_1_4: + size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3, + dest, + hpdev->desc.win_slot.slot, + cfg->vector); + break; + default: /* As we only negotiate protocol versions known to this driver, * this path should never hit. However, this is it not a hot |