Skip to content

Commit 11ebeae

Browse files
enesoztrkbrianmcgillion
authored andcommitted
fix: acs override to separate iommu groups
Signed-off-by: Enes Öztürk <enes.ozturk@unikie.com>
1 parent 4535be8 commit 11ebeae

File tree

7 files changed

+297
-26
lines changed

7 files changed

+297
-26
lines changed

REUSE.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ path = [
3636
"overlays/custom-packages/system76-scheduler/0001-fix-add-missing-loop-in-process-scheduler-refresh-ta.patch",
3737
"overlays/custom-packages/cosmic/cosmic-greeter/0001-Fix-softlock.patch",
3838
"overlays/custom-packages/cosmic/cosmic-greeter/0002-fix-username-handle-empty-usernames.patch",
39-
"modules/secureboot/keys/*"
39+
"modules/secureboot/keys/*",
40+
"modules/hardware/passthrough/pci-acs-override/0001-pci-add-pcie_acs_override-for-pci-passthrough.patch"
4041
]
4142

4243
[[annotations]]

modules/hardware/passthrough/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
imports = [
66
./evdev-rules.nix
77
./passthrough.nix
8+
./pci-acs-override/pci-acs-override.nix
89
./pci-ports.nix
910
./pci-rules.nix
1011
./usb-quirks.nix
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
From 4f9ce06d51e1e4574e80f2a30809f0cec6abbc0d Mon Sep 17 00:00:00 2001
2+
From: =?UTF-8?q?Enes=20=C3=96zt=C3=BCrk?= <enes.ozturk@unikie.com>
3+
Date: Fri, 16 Jan 2026 11:00:24 +0200
4+
Subject: [PATCH] pci: add pcie_acs_override for pci passthrough
5+
6+
Add kernel boot parameter pcie_acs_override to override missing PCIe
7+
ACS (Access Control Services) support for IOMMU grouping. This enables
8+
PCI passthrough for devices that don't properly implement ACS.
9+
10+
Usage: pcie_acs_override=id:vid:did[,id:vid:did...]
11+
Example: pcie_acs_override=id:8086:550a
12+
---
13+
.../admin-guide/kernel-parameters.txt | 6 ++
14+
drivers/pci/quirks.c | 82 +++++++++++++++++++
15+
2 files changed, 88 insertions(+)
16+
17+
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
18+
index 184f2f96f..e3483d4ac 100644
19+
--- a/Documentation/admin-guide/kernel-parameters.txt
20+
+++ b/Documentation/admin-guide/kernel-parameters.txt
21+
@@ -4309,6 +4309,12 @@
22+
nomsi [MSI] If the PCI_MSI kernel config parameter is
23+
enabled, this kernel boot option can be used to
24+
disable the use of MSI interrupts system-wide.
25+
+ pcie_acs_override=
26+
+ [PCIE] Override ACS for specific devices to isolate
27+
+ them into separate IOMMU groups.
28+
+ Format: id:vid:did[,id:vid:did...]
29+
+ vid:did = vendor:device ID in hex
30+
+ Example: pcie_acs_override=id:8086:550a
31+
noioapicquirk [APIC] Disable all boot interrupt quirks.
32+
Safety option to keep boot IRQs enabled. This
33+
should never be necessary.
34+
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
35+
index 70f484b81..c2b6792a4 100644
36+
--- a/drivers/pci/quirks.c
37+
+++ b/drivers/pci/quirks.c
38+
@@ -3740,6 +3740,87 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
39+
dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
40+
}
41+
42+
+#define NUM_ACS_IDS 16
43+
+struct acs_on_id {
44+
+ unsigned short vendor;
45+
+ unsigned short device;
46+
+};
47+
+static struct acs_on_id acs_on_ids[NUM_ACS_IDS];
48+
+static u8 max_acs_id;
49+
+
50+
+static __init int pcie_acs_override_setup(char *p)
51+
+{
52+
+ if (!p)
53+
+ return -EINVAL;
54+
+
55+
+ while (*p) {
56+
+ if (!strncmp(p, "id:", 3)) {
57+
+ char opt[5];
58+
+ int ret;
59+
+ long val;
60+
+
61+
+ if (max_acs_id >= NUM_ACS_IDS - 1) {
62+
+ pr_warn("pcie_acs_override: out of slots (%d)\n", NUM_ACS_IDS);
63+
+ goto next;
64+
+ }
65+
+
66+
+ p += 3;
67+
+ snprintf(opt, 5, "%s", p);
68+
+ ret = kstrtol(opt, 16, &val);
69+
+ if (ret) {
70+
+ pr_warn("pcie_acs_override: parse error %d\n", ret);
71+
+ goto next;
72+
+ }
73+
+ acs_on_ids[max_acs_id].vendor = val;
74+
+
75+
+ p += strcspn(p, ":");
76+
+ if (*p != ':') {
77+
+ pr_warn("pcie_acs_override: invalid ID format\n");
78+
+ goto next;
79+
+ }
80+
+
81+
+ p++;
82+
+ snprintf(opt, 5, "%s", p);
83+
+ ret = kstrtol(opt, 16, &val);
84+
+ if (ret) {
85+
+ pr_warn("pcie_acs_override: parse error %d\n", ret);
86+
+ goto next;
87+
+ }
88+
+ acs_on_ids[max_acs_id].device = val;
89+
+ pr_info("pcie_acs_override: added %04x:%04x\n",
90+
+ acs_on_ids[max_acs_id].vendor,
91+
+ acs_on_ids[max_acs_id].device);
92+
+ max_acs_id++;
93+
+ }
94+
+next:
95+
+ p += strcspn(p, ",");
96+
+ if (*p == ',')
97+
+ p++;
98+
+ }
99+
+
100+
+ if (max_acs_id)
101+
+ pr_warn("pcie_acs_override: %d device(s) will be isolated\n", max_acs_id);
102+
+
103+
+ return 0;
104+
+}
105+
+early_param("pcie_acs_override", pcie_acs_override_setup);
106+
+
107+
+static int pcie_acs_overrides(struct pci_dev *dev, u16 acs_flags)
108+
+{
109+
+ int i;
110+
+
111+
+ for (i = 0; i < max_acs_id; i++) {
112+
+ if (acs_on_ids[i].vendor == dev->vendor &&
113+
+ acs_on_ids[i].device == dev->device) {
114+
+ pr_info("pcie_acs_override: %04x:%04x isolated\n",
115+
+ dev->vendor, dev->device);
116+
+ return 1;
117+
+ }
118+
+ }
119+
+
120+
+ return -ENOTTY;
121+
+}
122+
+
123+
/*
124+
* Some NVIDIA GPU devices do not work with bus reset, SBR needs to be
125+
* prevented for those affected devices.
126+
@@ -5164,6 +5245,7 @@ static const struct pci_dev_acs_enabled {
127+
{ PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs },
128+
/* Wangxun nics */
129+
{ PCI_VENDOR_ID_WANGXUN, PCI_ANY_ID, pci_quirk_wangxun_nic_acs },
130+
+ { PCI_ANY_ID, PCI_ANY_ID, pcie_acs_overrides },
131+
{ 0 }
132+
};
133+
134+
--
135+
2.47.2
136+
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# SPDX-FileCopyrightText: 2022-2026 TII (SSRC) and the Ghaf contributors
2+
# SPDX-License-Identifier: Apache-2.0
3+
{
4+
config,
5+
lib,
6+
...
7+
}:
8+
let
9+
cfg = config.ghaf.hardware.passthrough.pciAcsOverride;
10+
hwDef = config.ghaf.hardware.definition;
11+
inherit (lib)
12+
mkEnableOption
13+
mkOption
14+
types
15+
mkIf
16+
;
17+
18+
# Convert device IDs to kernel parameter format (id:VENDOR:DEVICE)
19+
idOptions = map (id: "id:${id}") cfg.ids;
20+
21+
# Get all known PCI device IDs from all *.pciDevices in hardware definition
22+
allPciDevices = hwDef.network.pciDevices ++ hwDef.gpu.pciDevices ++ hwDef.audio.pciDevices;
23+
devicePciIds = map (dev: "${dev.vendorId}:${dev.productId}") (
24+
builtins.filter (dev: dev.vendorId != null && dev.productId != null) allPciDevices
25+
);
26+
27+
# Check which IDs are not in the hardware definition
28+
unmatchedIds = builtins.filter (id: !(builtins.elem id devicePciIds)) cfg.ids;
29+
in
30+
{
31+
options.ghaf.hardware.passthrough.pciAcsOverride = {
32+
enable = mkEnableOption "PCIe ACS (Access Control Services) override support for VFIO device assignment";
33+
34+
ids = mkOption {
35+
type = types.listOf types.str;
36+
default = [ ];
37+
example = [
38+
"8086:550a"
39+
"8086:7702"
40+
];
41+
description = ''
42+
List of specific PCI device IDs (vendor:device in hex) to override ACS.
43+
This works for ALL PCI devices including non-PCIe devices.
44+
45+
Use this when you need to split IOMMU groups for specific devices
46+
that are not PCIe (e.g., LPC/eSPI devices like Intel 00:1f.x).
47+
'';
48+
};
49+
};
50+
51+
config = mkIf cfg.enable {
52+
assertions = [
53+
{
54+
assertion = cfg.ids != [ ];
55+
message = "pciAcsOverride: 'ids' cannot be empty when enabled.";
56+
}
57+
{
58+
assertion = unmatchedIds == [ ];
59+
message = ''
60+
pciAcsOverride: IDs must match devices in hardware definition (*.pciDevices).
61+
Unmatched IDs: ${lib.concatStringsSep ", " unmatchedIds}
62+
Device PCI IDs: ${lib.concatStringsSep ", " devicePciIds}
63+
'';
64+
}
65+
];
66+
67+
boot.kernelPatches = [
68+
{
69+
name = "pci-acs-override";
70+
patch = ./0001-pci-add-pcie_acs_override-for-pci-passthrough.patch;
71+
}
72+
];
73+
74+
boot.kernelParams = [
75+
"pcie_acs_override=${lib.concatStringsSep "," idOptions}"
76+
];
77+
78+
warnings = [
79+
''
80+
PCIe ACS Override is enabled. This overrides hardware isolation boundaries
81+
and IOMMU group assignments. Only use this if you understand the security
82+
implications for your specific hardware topology and use case.
83+
84+
Device IDs: ${lib.concatStringsSep ", " cfg.ids}
85+
''
86+
];
87+
};
88+
}

modules/reference/hardware/dell-latitude/definitions/dell-latitude-7330.nix

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
# Network devices for passthrough to netvm
3737
network = {
38-
#TODO Add the Ethernet device
3938
pciDevices = [
4039
{
4140
# Network controller: Intel Corporation Wi-Fi 6E(802.11ax) AX210/AX1675* 2x2 [Typhoon Peak] (rev 1a)
@@ -47,11 +46,23 @@
4746
# Detected kernel driver: iwlwifi
4847
# Detected kernel modules: iwlwifi
4948
}
49+
{
50+
# Ethernet controller: Intel Corporation Ethernet Connection (13) I219-LM (rev 20)
51+
name = "eth0";
52+
path = "0000:00:1f.6";
53+
vendorId = "8086";
54+
productId = "15fb";
55+
# Detected kernel driver: e1000e
56+
# Detected kernel modules: e1000e
57+
}
5058
];
5159
kernelConfig = {
5260
# Kernel modules are indicative only, please investigate with lsmod/modinfo
5361
stage1.kernelModules = [ ];
54-
stage2.kernelModules = [ "iwlwifi" ];
62+
stage2.kernelModules = [
63+
"iwlwifi"
64+
"e1000e"
65+
];
5566
kernelParams = [ ];
5667
};
5768
};
@@ -79,7 +90,7 @@
7990

8091
# Audio device for passthrough to audiovm
8192
audio = {
82-
#TODO: Fix splitting the Ethernet from the Audio iommu
93+
8394
pciDevices = [
8495
{
8596
# ISA bridge: Intel Corporation Tiger Lake-LP LPC Controller (rev 20)
@@ -108,15 +119,6 @@
108119
# Detected kernel driver: snd_hda_intel
109120
# Detected kernel modules: snd_hda_intel,snd_sof_pci_intel_tgl
110121
}
111-
{
112-
# Ethernet controller: Intel Corporation Ethernet Connection (13) I219-LM (rev 20)
113-
name = "snd0-3";
114-
path = "0000:00:1f.6";
115-
vendorId = "8086";
116-
productId = "15fb";
117-
# Detected kernel driver: e1000e
118-
# Detected kernel modules: e1000e
119-
}
120122
{
121123
# SMBus: Intel Corporation Tiger Lake-LP SMBus Controller (rev 20)
122124
name = "snd0-4";
@@ -131,7 +133,6 @@
131133
# Kernel modules are indicative only, please investigate with lsmod/modinfo
132134
stage1.kernelModules = [ ];
133135
stage2.kernelModules = [
134-
"e1000e"
135136
"i2c_i801"
136137
"snd_hda_intel"
137138
"snd_sof_pci_intel_tgl"

modules/reference/hardware/system76/definitions/system76-darp11-b.nix

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,23 @@
4444
# Detected kernel driver: iwlwifi
4545
# Detected kernel modules: iwlwifi
4646
}
47+
{
48+
# Ethernet controller: Intel Corporation Device 550a
49+
# NOTE: This device is in the same IOMMU group as audio devices (0000:00:1f.x).
50+
# PCI ACS override is enabled in the laptop configuration to split this group.
51+
name = "eth0";
52+
path = "0000:00:1f.6";
53+
vendorId = "8086";
54+
productId = "550a";
55+
# Detected kernel driver: e1000e
56+
# Detected kernel modules: e1000e
57+
}
4758
];
59+
kernelConfig = {
60+
stage2.kernelModules = [
61+
"e1000e"
62+
];
63+
};
4864
};
4965

5066
# GPU devices for passthrough to guivm
@@ -111,20 +127,9 @@
111127
# Detected kernel driver: i801_smbus
112128
# Detected kernel modules: i2c_i801
113129
}
114-
# TODO: Fix splitting the Ethernet from the Audio iommu
115-
{
116-
# Ethernet controller: Intel Corporation Device 550a
117-
name = "snd0-4";
118-
path = "0000:00:1f.6";
119-
vendorId = "8086";
120-
productId = "550a";
121-
# Detected kernel driver: e1000e
122-
# Detected kernel modules: e1000e
123-
}
124130
];
125131
kernelConfig = {
126132
stage2.kernelModules = [
127-
"e1000e"
128133
"i2c_i801"
129134
"snd_hda_intel"
130135
"snd_sof_pci_intel_mtl"

0 commit comments

Comments
 (0)