Skip to content

Commit a2bad84

Browse files
quic-jhugoliuw
authored andcommitted
PCI: hv: Fix interrupt mapping for multi-MSI
According to Dexuan, the hypervisor folks beleive that multi-msi allocations are not correct. compose_msi_msg() will allocate multi-msi one by one. However, multi-msi is a block of related MSIs, with alignment requirements. In order for the hypervisor to allocate properly aligned and consecutive entries in the IOMMU Interrupt Remapping Table, there should be a single mapping request that requests all of the multi-msi vectors in one shot. Dexuan suggests detecting the multi-msi case and composing a single request related to the first MSI. Then for the other MSIs in the same block, use the cached information. This appears to be viable, so do it. Suggested-by: Dexuan Cui <decui@microsoft.com> Signed-off-by: Jeffrey Hugo <quic_jhugo@quicinc.com> Reviewed-by: Dexuan Cui <decui@microsoft.com> Tested-by: Michael Kelley <mikelley@microsoft.com> Link: https://lore.kernel.org/r/1652282599-21643-1-git-send-email-quic_jhugo@quicinc.com Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent b4b7777 commit a2bad84

1 file changed

Lines changed: 50 additions & 10 deletions

File tree

drivers/pci/controller/pci-hyperv.c

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,10 @@ static void hv_int_desc_free(struct hv_pci_dev *hpdev,
15251525
u8 buffer[sizeof(struct pci_delete_interrupt)];
15261526
} ctxt;
15271527

1528+
if (!int_desc->vector_count) {
1529+
kfree(int_desc);
1530+
return;
1531+
}
15281532
memset(&ctxt, 0, sizeof(ctxt));
15291533
int_pkt = (struct pci_delete_interrupt *)&ctxt.pkt.message;
15301534
int_pkt->message_type.type =
@@ -1609,12 +1613,12 @@ static void hv_pci_compose_compl(void *context, struct pci_response *resp,
16091613

16101614
static u32 hv_compose_msi_req_v1(
16111615
struct pci_create_interrupt *int_pkt, struct cpumask *affinity,
1612-
u32 slot, u8 vector)
1616+
u32 slot, u8 vector, u8 vector_count)
16131617
{
16141618
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE;
16151619
int_pkt->wslot.slot = slot;
16161620
int_pkt->int_desc.vector = vector;
1617-
int_pkt->int_desc.vector_count = 1;
1621+
int_pkt->int_desc.vector_count = vector_count;
16181622
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
16191623

16201624
/*
@@ -1637,14 +1641,14 @@ static int hv_compose_msi_req_get_cpu(struct cpumask *affinity)
16371641

16381642
static u32 hv_compose_msi_req_v2(
16391643
struct pci_create_interrupt2 *int_pkt, struct cpumask *affinity,
1640-
u32 slot, u8 vector)
1644+
u32 slot, u8 vector, u8 vector_count)
16411645
{
16421646
int cpu;
16431647

16441648
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE2;
16451649
int_pkt->wslot.slot = slot;
16461650
int_pkt->int_desc.vector = vector;
1647-
int_pkt->int_desc.vector_count = 1;
1651+
int_pkt->int_desc.vector_count = vector_count;
16481652
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
16491653
cpu = hv_compose_msi_req_get_cpu(affinity);
16501654
int_pkt->int_desc.processor_array[0] =
@@ -1656,15 +1660,15 @@ static u32 hv_compose_msi_req_v2(
16561660

16571661
static u32 hv_compose_msi_req_v3(
16581662
struct pci_create_interrupt3 *int_pkt, struct cpumask *affinity,
1659-
u32 slot, u32 vector)
1663+
u32 slot, u32 vector, u8 vector_count)
16601664
{
16611665
int cpu;
16621666

16631667
int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE3;
16641668
int_pkt->wslot.slot = slot;
16651669
int_pkt->int_desc.vector = vector;
16661670
int_pkt->int_desc.reserved = 0;
1667-
int_pkt->int_desc.vector_count = 1;
1671+
int_pkt->int_desc.vector_count = vector_count;
16681672
int_pkt->int_desc.delivery_mode = DELIVERY_MODE;
16691673
cpu = hv_compose_msi_req_get_cpu(affinity);
16701674
int_pkt->int_desc.processor_array[0] =
@@ -1695,6 +1699,8 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
16951699
struct cpumask *dest;
16961700
struct compose_comp_ctxt comp;
16971701
struct tran_int_desc *int_desc;
1702+
struct msi_desc *msi_desc;
1703+
u8 vector, vector_count;
16981704
struct {
16991705
struct pci_packet pci_pkt;
17001706
union {
@@ -1716,7 +1722,8 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
17161722
return;
17171723
}
17181724

1719-
pdev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
1725+
msi_desc = irq_data_get_msi_desc(data);
1726+
pdev = msi_desc_to_pci_dev(msi_desc);
17201727
dest = irq_data_get_effective_affinity_mask(data);
17211728
pbus = pdev->bus;
17221729
hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
@@ -1729,6 +1736,36 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
17291736
if (!int_desc)
17301737
goto drop_reference;
17311738

1739+
if (!msi_desc->pci.msi_attrib.is_msix && msi_desc->nvec_used > 1) {
1740+
/*
1741+
* If this is not the first MSI of Multi MSI, we already have
1742+
* a mapping. Can exit early.
1743+
*/
1744+
if (msi_desc->irq != data->irq) {
1745+
data->chip_data = int_desc;
1746+
int_desc->address = msi_desc->msg.address_lo |
1747+
(u64)msi_desc->msg.address_hi << 32;
1748+
int_desc->data = msi_desc->msg.data +
1749+
(data->irq - msi_desc->irq);
1750+
msg->address_hi = msi_desc->msg.address_hi;
1751+
msg->address_lo = msi_desc->msg.address_lo;
1752+
msg->data = int_desc->data;
1753+
put_pcichild(hpdev);
1754+
return;
1755+
}
1756+
/*
1757+
* The vector we select here is a dummy value. The correct
1758+
* value gets sent to the hypervisor in unmask(). This needs
1759+
* to be aligned with the count, and also not zero. Multi-msi
1760+
* is powers of 2 up to 32, so 32 will always work here.
1761+
*/
1762+
vector = 32;
1763+
vector_count = msi_desc->nvec_used;
1764+
} else {
1765+
vector = hv_msi_get_int_vector(data);
1766+
vector_count = 1;
1767+
}
1768+
17321769
memset(&ctxt, 0, sizeof(ctxt));
17331770
init_completion(&comp.comp_pkt.host_event);
17341771
ctxt.pci_pkt.completion_func = hv_pci_compose_compl;
@@ -1739,22 +1776,25 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
17391776
size = hv_compose_msi_req_v1(&ctxt.int_pkts.v1,
17401777
dest,
17411778
hpdev->desc.win_slot.slot,
1742-
hv_msi_get_int_vector(data));
1779+
vector,
1780+
vector_count);
17431781
break;
17441782

17451783
case PCI_PROTOCOL_VERSION_1_2:
17461784
case PCI_PROTOCOL_VERSION_1_3:
17471785
size = hv_compose_msi_req_v2(&ctxt.int_pkts.v2,
17481786
dest,
17491787
hpdev->desc.win_slot.slot,
1750-
hv_msi_get_int_vector(data));
1788+
vector,
1789+
vector_count);
17511790
break;
17521791

17531792
case PCI_PROTOCOL_VERSION_1_4:
17541793
size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3,
17551794
dest,
17561795
hpdev->desc.win_slot.slot,
1757-
hv_msi_get_int_vector(data));
1796+
vector,
1797+
vector_count);
17581798
break;
17591799

17601800
default:

0 commit comments

Comments
 (0)