PCI/TPH: Replace the broken MSI-X control word update
The driver walks the MSI descriptors to test whether a descriptor exists for a given index. That's just abuse of the MSI internals. The same test can be done with a single function call by looking up whether there is a Linux interrupt number assigned at the index. What's worse is that the function is completely unserialized against modifications of the MSI-X control by operations issued from the interrupt core. It also brings the PCI/MSI-X internal cached control word out of sync. Remove the trainwreck and invoke the function provided by the PCI/MSI core to update it. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://lore.kernel.org/all/20250313130321.898592817@linutronix.de
This commit is contained in:
@@ -204,48 +204,6 @@ static u8 get_rp_completer_type(struct pci_dev *pdev)
|
||||
return FIELD_GET(PCI_EXP_DEVCAP2_TPH_COMP_MASK, reg);
|
||||
}
|
||||
|
||||
/* Write ST to MSI-X vector control reg - Return 0 if OK, otherwise -errno */
|
||||
static int write_tag_to_msix(struct pci_dev *pdev, int msix_idx, u16 tag)
|
||||
{
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
struct msi_desc *msi_desc = NULL;
|
||||
void __iomem *vec_ctrl;
|
||||
u32 val;
|
||||
int err = 0;
|
||||
|
||||
msi_lock_descs(&pdev->dev);
|
||||
|
||||
/* Find the msi_desc entry with matching msix_idx */
|
||||
msi_for_each_desc(msi_desc, &pdev->dev, MSI_DESC_ASSOCIATED) {
|
||||
if (msi_desc->msi_index == msix_idx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!msi_desc) {
|
||||
err = -ENXIO;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Get the vector control register (offset 0xc) pointed by msix_idx */
|
||||
vec_ctrl = pdev->msix_base + msix_idx * PCI_MSIX_ENTRY_SIZE;
|
||||
vec_ctrl += PCI_MSIX_ENTRY_VECTOR_CTRL;
|
||||
|
||||
val = readl(vec_ctrl);
|
||||
val &= ~PCI_MSIX_ENTRY_CTRL_ST;
|
||||
val |= FIELD_PREP(PCI_MSIX_ENTRY_CTRL_ST, tag);
|
||||
writel(val, vec_ctrl);
|
||||
|
||||
/* Read back to flush the update */
|
||||
val = readl(vec_ctrl);
|
||||
|
||||
err_out:
|
||||
msi_unlock_descs(&pdev->dev);
|
||||
return err;
|
||||
#else
|
||||
return -ENODEV;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Write tag to ST table - Return 0 if OK, otherwise -errno */
|
||||
static int write_tag_to_st_table(struct pci_dev *pdev, int index, u16 tag)
|
||||
{
|
||||
@@ -346,7 +304,7 @@ int pcie_tph_set_st_entry(struct pci_dev *pdev, unsigned int index, u16 tag)
|
||||
|
||||
switch (loc) {
|
||||
case PCI_TPH_LOC_MSIX:
|
||||
err = write_tag_to_msix(pdev, index, tag);
|
||||
err = pci_msix_write_tph_tag(pdev, index, tag);
|
||||
break;
|
||||
case PCI_TPH_LOC_CAP:
|
||||
err = write_tag_to_st_table(pdev, index, tag);
|
||||
|
||||
Reference in New Issue
Block a user