[SRU][R][PATCH 2/2] UBUNTU: SAUCE: PCI: vmd: Work around ARL004 on 8086:ad0b
Vladimir Nedoshivin
gvozd188 at mail.ru
Tue Sep 8 22:00:47 UTC 2026
BugLink: https://bugs.launchpad.net/bugs/2166325
Intel Arrow Lake VMD device 8086:ad0b is affected by ARL004. A posted
write from a device behind VMD may not be globally visible when the MSI
is observed by the VMD interrupt handler.
For NVMe devices behind 8086:ad0b, retain a configuration-space address
for the MSI initiator and issue a dummy read before dispatching the
interrupt. The read flushes outstanding posted writes before the NVMe
completion interrupt is handled.
Limit the workaround to VMD device 8086:ad0b and NVMe endpoints.
The workaround has been tested on the affected Arrow Lake system with
Ubuntu 7.0.0-31-generic.
Signed-off-by: Vladimir Nedoshivin <gvozd188 at mail.ru>
---
drivers/pci/controller/vmd.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index 59fe330..ae4f8c1 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -194,6 +194,9 @@ static inline struct vmd_dev *vmd_from_bus(struct pci_bus *bus)
return container_of(bus->sysdata, struct vmd_dev, sysdata);
}
+static void __iomem *vmd_cfg_addr(struct vmd_dev *vmd, struct pci_bus *bus,
+ unsigned int devfn, int reg, int len);
+
static inline unsigned int index_from_irqs(struct vmd_dev *vmd,
struct vmd_irq_list *irqs)
{
@@ -312,6 +315,7 @@ static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq,
{
struct msi_desc *desc = ((msi_alloc_info_t *)arg)->desc;
struct vmd_dev *vmd = domain->host_data;
+ struct pci_dev *pdev = msi_desc_to_pci_dev(desc);
struct vmd_irq *vmdirq;
for (int i = 0; i < nr_irqs; ++i) {
@@ -325,6 +329,11 @@ static int vmd_msi_alloc(struct irq_domain *domain, unsigned int virq,
vmdirq->irq = vmd_next_irq(vmd, desc);
vmdirq->virq = virq + i;
+ if (vmd->dev->device == 0xad0b &&
+ pdev->class == PCI_CLASS_STORAGE_EXPRESS)
+ vmdirq->flush_addr = vmd_cfg_addr(vmd, pdev->bus,
+ pdev->devfn, PCI_DEVICE_ID, 2);
+
irq_domain_set_info(domain, virq + i, vmdirq->irq->virq,
&vmd_msi_controller, vmdirq,
handle_untracked_irq, vmd, NULL);
@@ -754,11 +763,18 @@ static irqreturn_t vmd_irq(int irq, void *data)
{
struct vmd_irq_list *irqs = data;
struct vmd_irq *vmdirq;
+ unsigned long flags;
int idx;
idx = srcu_read_lock(&irqs->srcu);
- list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node)
+ list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) {
+ if (vmdirq->flush_addr) {
+ raw_spin_lock_irqsave(&irqs->vmd->cfg_lock, flags);
+ readw(vmdirq->flush_addr);
+ raw_spin_unlock_irqrestore(&irqs->vmd->cfg_lock, flags);
+ }
generic_handle_irq(vmdirq->virq);
+ }
srcu_read_unlock(&irqs->srcu, idx);
return IRQ_HANDLED;
@@ -789,6 +805,7 @@ static int vmd_alloc_irqs(struct vmd_dev *vmd)
return err;
INIT_LIST_HEAD(&vmd->irqs[i].irq_list);
+ vmd->irqs[i].vmd = vmd;
vmd->irqs[i].virq = pci_irq_vector(dev, i);
err = devm_request_irq(&dev->dev, vmd->irqs[i].virq,
vmd_irq, IRQF_NO_THREAD,
--
2.53.0
More information about the kernel-team
mailing list