summaryrefslogtreecommitdiff
path: root/sys-kernel/gentoo-sources/override_for_missing_acs_capabilities.patch
blob: 00f864ea84c2d915f58e24689070259f7d18dade (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
--- a/drivers/pci/quirks.c	2020-05-12 20:48:40.153152132 +0300
+++ b/drivers/pci/quirks.c	2020-05-13 15:59:18.477619314 +0300
@@ -4695,6 +4695,111 @@
 		PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF);
 }
 
+/*
+* PCIe ACS Override
+*/
+static bool acs_on_downstream;
+static bool acs_on_multifunction;
+
+#define NUM_ACS_IDS 16
+struct acs_on_id {
+	unsigned short vendor;
+	unsigned short device;
+};
+static struct acs_on_id acs_on_ids[NUM_ACS_IDS];
+static u8 max_acs_id;
+
+static __init int pcie_acs_override_setup(char *p)
+{
+       if (!p)
+               return -EINVAL;
+
+       while (*p) {
+               if (!strncmp(p, "downstream", 10))
+                       acs_on_downstream = true;
+               if (!strncmp(p, "multifunction", 13))
+                       acs_on_multifunction = true;
+               if (!strncmp(p, "id:", 3)) {
+                       char opt[5];
+                       int ret;
+                       long val;
+
+                       if (max_acs_id >= NUM_ACS_IDS - 1) {
+                               pr_warn("Out of PCIe ACS override slots (%d)\n",
+                                       NUM_ACS_IDS);
+                               goto next;
+                       }
+
+                       p += 3;
+                       snprintf(opt, 5, "%s", p);
+                       ret = kstrtol(opt, 16, &val);
+                       if (ret) {
+                               pr_warn("PCIe ACS ID parse error %d\n", ret);
+                               goto next;
+                       }
+                       acs_on_ids[max_acs_id].vendor = val;
+
+                       p += strcspn(p, ":");
+                       if (*p != ':') {
+                               pr_warn("PCIe ACS invalid ID\n");
+                               goto next;
+                       }
+
+                       p++;
+                       snprintf(opt, 5, "%s", p);
+                       ret = kstrtol(opt, 16, &val);
+                       if (ret) {
+                               pr_warn("PCIe ACS ID parse error %d\n", ret);
+                               goto next;
+                       }
+                       acs_on_ids[max_acs_id].device = val;
+                       max_acs_id++;
+               }
+next:
+               p += strcspn(p, ",");
+               if (*p == ',')
+                       p++;
+       }
+
+       if (acs_on_downstream || acs_on_multifunction || max_acs_id)
+               pr_warn("Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n");
+
+       return 0;
+}
+
+early_param("pcie_acs_override", pcie_acs_override_setup);
+
+static int pcie_acs_overrides(struct pci_dev *dev, u16 acs_flags)
+{
+       int i;
+
+       /* Never override ACS for legacy devices or devices with ACS caps */
+       if (!pci_is_pcie(dev) ||
+           pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS))
+               return -ENOTTY;
+
+       for (i = 0; i < max_acs_id; i++)
+               if (acs_on_ids[i].vendor == dev->vendor &&
+                   acs_on_ids[i].device == dev->device)
+                       return 1;
+
+       switch (pci_pcie_type(dev)) {
+       case PCI_EXP_TYPE_DOWNSTREAM:
+       case PCI_EXP_TYPE_ROOT_PORT:
+               if (acs_on_downstream)
+                       return 1;
+               break;
+       case PCI_EXP_TYPE_ENDPOINT:
+       case PCI_EXP_TYPE_UPSTREAM:
+       case PCI_EXP_TYPE_LEG_END:
+       case PCI_EXP_TYPE_RC_END:
+               if (acs_on_multifunction && dev->multifunction)
+                       return 1;
+       }
+
+       return -ENOTTY;
+}
+
 static const struct pci_dev_acs_enabled {
 	u16 vendor;
 	u16 device;
@@ -5001,6 +5001,8 @@
 	/* Zhaoxin Root/Downstream Ports */
 	{ PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs },
	/* Wangxun nics */
	{ PCI_VENDOR_ID_WANGXUN, PCI_ANY_ID, pci_quirk_wangxun_nic_acs },
+	/* IOMMU ACS override patch */
+	{ PCI_ANY_ID, PCI_ANY_ID, pcie_acs_overrides },
 	{ 0 }
 };