]>
Commit | Line | Data |
---|---|---|
1 | From d4ed2b803ac71237701ecd08e46b0e30bdad099c Mon Sep 17 00:00:00 2001 | |
2 | From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= <ayufan@ayufan.eu> | |
3 | Date: Fri, 13 Jun 2014 23:40:11 +0200 | |
4 | Subject: [PATCH 3/4] override_for_missing_acs_capabilities.patch | |
5 | ||
6 | ||
7 | Signed-off-by: Alexandre Derumier <aderumier@odiso.com> | |
8 | --- | |
9 | Documentation/kernel-parameters.txt | 10 ++++ | |
10 | drivers/pci/quirks.c | 103 +++++++++++++++++++++++++++++++++++ | |
11 | 2 files changed, 113 insertions(+) | |
12 | ||
13 | diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt | |
14 | index 30a8ad0d..ea1b3fe 100644 | |
15 | --- a/Documentation/kernel-parameters.txt | |
16 | +++ b/Documentation/kernel-parameters.txt | |
17 | @@ -2554,6 +2554,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |
18 | nomsi Do not use MSI for native PCIe PME signaling (this makes | |
19 | all PCIe root ports use INTx for all services). | |
20 | ||
21 | + pcie_acs_override = | |
22 | + [PCIE] Override missing PCIe ACS support for: | |
23 | + downstream | |
24 | + All downstream ports - full ACS capabilties | |
25 | + multifunction | |
26 | + All multifunction devices - multifunction ACS subset | |
27 | + id:nnnn:nnnn | |
28 | + Specfic device - full ACS capabilities | |
29 | + Specified as vid:did (vendor/device ID) in hex | |
30 | + | |
31 | pcmv= [HW,PCMCIA] BadgePAD 4 | |
32 | ||
33 | pd_ignore_unused | |
34 | diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c | |
35 | index e729206..e38c80d 100644 | |
36 | --- a/drivers/pci/quirks.c | |
37 | +++ b/drivers/pci/quirks.c | |
38 | @@ -3384,6 +3384,107 @@ struct pci_dev *pci_get_dma_source(struct pci_dev *dev) | |
39 | return pci_dev_get(dev); | |
40 | } | |
41 | ||
42 | +static bool acs_on_downstream; | |
43 | +static bool acs_on_multifunction; | |
44 | + | |
45 | +#define NUM_ACS_IDS 16 | |
46 | +struct acs_on_id { | |
47 | + unsigned short vendor; | |
48 | + unsigned short device; | |
49 | +}; | |
50 | +static struct acs_on_id acs_on_ids[NUM_ACS_IDS]; | |
51 | +static u8 max_acs_id; | |
52 | + | |
53 | +static __init int pcie_acs_override_setup(char *p) | |
54 | +{ | |
55 | + if (!p) | |
56 | + return -EINVAL; | |
57 | + | |
58 | + while (*p) { | |
59 | + if (!strncmp(p, "downstream", 10)) | |
60 | + acs_on_downstream = true; | |
61 | + if (!strncmp(p, "multifunction", 13)) | |
62 | + acs_on_multifunction = true; | |
63 | + if (!strncmp(p, "id:", 3)) { | |
64 | + char opt[5]; | |
65 | + int ret; | |
66 | + long val; | |
67 | + | |
68 | + if (max_acs_id >= NUM_ACS_IDS - 1) { | |
69 | + pr_warn("Out of PCIe ACS override slots (%d)\n", | |
70 | + NUM_ACS_IDS); | |
71 | + goto next; | |
72 | + } | |
73 | + | |
74 | + p += 3; | |
75 | + snprintf(opt, 5, "%s", p); | |
76 | + ret = kstrtol(opt, 16, &val); | |
77 | + if (ret) { | |
78 | + pr_warn("PCIe ACS ID parse error %d\n", ret); | |
79 | + goto next; | |
80 | + } | |
81 | + acs_on_ids[max_acs_id].vendor = val; | |
82 | + | |
83 | + p += strcspn(p, ":"); | |
84 | + if (*p != ':') { | |
85 | + pr_warn("PCIe ACS invalid ID\n"); | |
86 | + goto next; | |
87 | + } | |
88 | + | |
89 | + p++; | |
90 | + snprintf(opt, 5, "%s", p); | |
91 | + ret = kstrtol(opt, 16, &val); | |
92 | + if (ret) { | |
93 | + pr_warn("PCIe ACS ID parse error %d\n", ret); | |
94 | + goto next; | |
95 | + } | |
96 | + acs_on_ids[max_acs_id].device = val; | |
97 | + max_acs_id++; | |
98 | + } | |
99 | +next: | |
100 | + p += strcspn(p, ","); | |
101 | + if (*p == ',') | |
102 | + p++; | |
103 | + } | |
104 | + | |
105 | + if (acs_on_downstream || acs_on_multifunction || max_acs_id) | |
106 | + pr_warn("Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n"); | |
107 | + | |
108 | + return 0; | |
109 | +} | |
110 | +early_param("pcie_acs_override", pcie_acs_override_setup); | |
111 | + | |
112 | +static int pcie_acs_overrides(struct pci_dev *dev, u16 acs_flags) | |
113 | +{ | |
114 | + int i; | |
115 | + | |
116 | + /* Never override ACS for legacy devices or devices with ACS caps */ | |
117 | + if (!pci_is_pcie(dev) || | |
118 | + pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS)) | |
119 | + return -ENOTTY; | |
120 | + | |
121 | + for (i = 0; i < max_acs_id; i++) | |
122 | + if (acs_on_ids[i].vendor == dev->vendor && | |
123 | + acs_on_ids[i].device == dev->device) | |
124 | + return 1; | |
125 | + | |
126 | + switch (pci_pcie_type(dev)) { | |
127 | + case PCI_EXP_TYPE_DOWNSTREAM: | |
128 | + case PCI_EXP_TYPE_ROOT_PORT: | |
129 | + if (acs_on_downstream) | |
130 | + return 1; | |
131 | + break; | |
132 | + case PCI_EXP_TYPE_ENDPOINT: | |
133 | + case PCI_EXP_TYPE_UPSTREAM: | |
134 | + case PCI_EXP_TYPE_LEG_END: | |
135 | + case PCI_EXP_TYPE_RC_END: | |
136 | + if (acs_on_multifunction && dev->multifunction) | |
137 | + return 1; | |
138 | + } | |
139 | + | |
140 | + return -ENOTTY; | |
141 | +} | |
142 | + | |
143 | /* | |
144 | * AMD has indicated that the devices below do not support peer-to-peer | |
145 | * in any system where they are found in the southbridge with an AMD | |
146 | @@ -3483,6 +3584,7 @@ static int pci_quirk_intel_pch_acs(struct pci_dev *dev, u16 acs_flags) | |
147 | return acs_flags & ~flags ? 0 : 1; | |
148 | } | |
149 | ||
150 | + | |
151 | static const struct pci_dev_acs_enabled { | |
152 | u16 vendor; | |
153 | u16 device; | |
154 | @@ -3495,6 +3597,7 @@ static const struct pci_dev_acs_enabled { | |
155 | { PCI_VENDOR_ID_ATI, 0x4384, pci_quirk_amd_sb_acs }, | |
156 | { PCI_VENDOR_ID_ATI, 0x4399, pci_quirk_amd_sb_acs }, | |
157 | { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs }, | |
158 | + { PCI_ANY_ID, PCI_ANY_ID, pcie_acs_overrides }, | |
159 | { 0 } | |
160 | }; | |
161 | ||
162 | -- | |
163 | 1.7.10.4 | |
164 |