]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Suresh Siddha <suresh.b.siddha@intel.com> |
2 | Subject: x64, x2apic/intr-remap: code re-structuring, to be used by both DMA and Interrupt remapping | |
3 | References: fate #303948 and fate #303984 | |
4 | Patch-Mainline: queued for .28 | |
5 | Commit-ID: 1886e8a90a580f3ad343f2065c84c1b9e1dac9ef | |
6 | ||
7 | Signed-off-by: Thomas Renninger <trenn@suse.de> | |
8 | ||
9 | Allocate the iommu during the parse of DMA remapping hardware | |
10 | definition structures. And also, introduce routines for device | |
11 | scope initialization which will be explicitly called during | |
12 | dma-remapping initialization. | |
13 | ||
14 | These will be used for enabling interrupt remapping separately from the | |
15 | existing DMA-remapping enabling sequence. | |
16 | ||
17 | Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> | |
18 | Cc: akpm@linux-foundation.org | |
19 | Cc: arjan@linux.intel.com | |
20 | Cc: andi@firstfloor.org | |
21 | Cc: ebiederm@xmission.com | |
22 | Cc: jbarnes@virtuousgeek.org | |
23 | Cc: steiner@sgi.com | |
24 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
25 | ||
26 | --- | |
27 | drivers/pci/dmar.c | 89 +++++++++++++++++++++++++++++++++++++--------- | |
28 | drivers/pci/intel-iommu.c | 10 ++--- | |
29 | drivers/pci/intel-iommu.h | 2 - | |
30 | include/linux/dmar.h | 10 ++++- | |
31 | 4 files changed, 88 insertions(+), 23 deletions(-) | |
32 | ||
33 | --- a/drivers/pci/dmar.c | |
34 | +++ b/drivers/pci/dmar.c | |
35 | @@ -174,19 +174,37 @@ dmar_parse_one_drhd(struct acpi_dmar_hea | |
36 | struct acpi_dmar_hardware_unit *drhd; | |
37 | struct dmar_drhd_unit *dmaru; | |
38 | int ret = 0; | |
39 | - static int include_all; | |
40 | ||
41 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); | |
42 | if (!dmaru) | |
43 | return -ENOMEM; | |
44 | ||
45 | + dmaru->hdr = header; | |
46 | drhd = (struct acpi_dmar_hardware_unit *)header; | |
47 | dmaru->reg_base_addr = drhd->address; | |
48 | dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ | |
49 | ||
50 | + ret = alloc_iommu(dmaru); | |
51 | + if (ret) { | |
52 | + kfree(dmaru); | |
53 | + return ret; | |
54 | + } | |
55 | + dmar_register_drhd_unit(dmaru); | |
56 | + return 0; | |
57 | +} | |
58 | + | |
59 | +static int __init | |
60 | +dmar_parse_dev(struct dmar_drhd_unit *dmaru) | |
61 | +{ | |
62 | + struct acpi_dmar_hardware_unit *drhd; | |
63 | + static int include_all; | |
64 | + int ret; | |
65 | + | |
66 | + drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; | |
67 | + | |
68 | if (!dmaru->include_all) | |
69 | ret = dmar_parse_dev_scope((void *)(drhd + 1), | |
70 | - ((void *)drhd) + header->length, | |
71 | + ((void *)drhd) + drhd->header.length, | |
72 | &dmaru->devices_cnt, &dmaru->devices, | |
73 | drhd->segment); | |
74 | else { | |
75 | @@ -199,10 +217,10 @@ dmar_parse_one_drhd(struct acpi_dmar_hea | |
76 | include_all = 1; | |
77 | } | |
78 | ||
79 | - if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) | |
80 | + if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) { | |
81 | + list_del(&dmaru->list); | |
82 | kfree(dmaru); | |
83 | - else | |
84 | - dmar_register_drhd_unit(dmaru); | |
85 | + } | |
86 | return ret; | |
87 | } | |
88 | ||
89 | @@ -211,23 +229,35 @@ dmar_parse_one_rmrr(struct acpi_dmar_hea | |
90 | { | |
91 | struct acpi_dmar_reserved_memory *rmrr; | |
92 | struct dmar_rmrr_unit *rmrru; | |
93 | - int ret = 0; | |
94 | ||
95 | rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); | |
96 | if (!rmrru) | |
97 | return -ENOMEM; | |
98 | ||
99 | + rmrru->hdr = header; | |
100 | rmrr = (struct acpi_dmar_reserved_memory *)header; | |
101 | rmrru->base_address = rmrr->base_address; | |
102 | rmrru->end_address = rmrr->end_address; | |
103 | + | |
104 | + dmar_register_rmrr_unit(rmrru); | |
105 | + return 0; | |
106 | +} | |
107 | + | |
108 | +static int __init | |
109 | +rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | |
110 | +{ | |
111 | + struct acpi_dmar_reserved_memory *rmrr; | |
112 | + int ret; | |
113 | + | |
114 | + rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; | |
115 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), | |
116 | - ((void *)rmrr) + header->length, | |
117 | + ((void *)rmrr) + rmrr->header.length, | |
118 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); | |
119 | ||
120 | - if (ret || (rmrru->devices_cnt == 0)) | |
121 | + if (ret || (rmrru->devices_cnt == 0)) { | |
122 | + list_del(&rmrru->list); | |
123 | kfree(rmrru); | |
124 | - else | |
125 | - dmar_register_rmrr_unit(rmrru); | |
126 | + } | |
127 | return ret; | |
128 | } | |
129 | ||
130 | @@ -333,15 +363,42 @@ dmar_find_matched_drhd_unit(struct pci_d | |
131 | return NULL; | |
132 | } | |
133 | ||
134 | +int __init dmar_dev_scope_init(void) | |
135 | +{ | |
136 | + struct dmar_drhd_unit *drhd; | |
137 | + struct dmar_rmrr_unit *rmrr; | |
138 | + int ret = -ENODEV; | |
139 | + | |
140 | + for_each_drhd_unit(drhd) { | |
141 | + ret = dmar_parse_dev(drhd); | |
142 | + if (ret) | |
143 | + return ret; | |
144 | + } | |
145 | + | |
146 | + for_each_rmrr_units(rmrr) { | |
147 | + ret = rmrr_parse_dev(rmrr); | |
148 | + if (ret) | |
149 | + return ret; | |
150 | + } | |
151 | + | |
152 | + return ret; | |
153 | +} | |
154 | + | |
155 | ||
156 | int __init dmar_table_init(void) | |
157 | { | |
158 | - | |
159 | + static int dmar_table_initialized; | |
160 | int ret; | |
161 | ||
162 | + if (dmar_table_initialized) | |
163 | + return 0; | |
164 | + | |
165 | + dmar_table_initialized = 1; | |
166 | + | |
167 | ret = parse_dmar_table(); | |
168 | if (ret) { | |
169 | - printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); | |
170 | + if (ret != -ENODEV) | |
171 | + printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); | |
172 | return ret; | |
173 | } | |
174 | ||
175 | @@ -375,7 +432,7 @@ int __init early_dmar_detect(void) | |
176 | return (ACPI_SUCCESS(status) ? 1 : 0); | |
177 | } | |
178 | ||
179 | -struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) | |
180 | +int alloc_iommu(struct dmar_drhd_unit *drhd) | |
181 | { | |
182 | struct intel_iommu *iommu; | |
183 | int map_size; | |
184 | @@ -384,7 +441,7 @@ struct intel_iommu *alloc_iommu(struct d | |
185 | ||
186 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | |
187 | if (!iommu) | |
188 | - return NULL; | |
189 | + return -ENOMEM; | |
190 | ||
191 | iommu->seq_id = iommu_allocated++; | |
192 | ||
193 | @@ -417,10 +474,10 @@ struct intel_iommu *alloc_iommu(struct d | |
194 | spin_lock_init(&iommu->register_lock); | |
195 | ||
196 | drhd->iommu = iommu; | |
197 | - return iommu; | |
198 | + return 0; | |
199 | error: | |
200 | kfree(iommu); | |
201 | - return NULL; | |
202 | + return -1; | |
203 | } | |
204 | ||
205 | void free_iommu(struct intel_iommu *iommu) | |
206 | --- a/drivers/pci/intel-iommu.c | |
207 | +++ b/drivers/pci/intel-iommu.c | |
208 | @@ -1667,11 +1667,8 @@ int __init init_dmars(void) | |
209 | for_each_drhd_unit(drhd) { | |
210 | if (drhd->ignored) | |
211 | continue; | |
212 | - iommu = alloc_iommu(drhd); | |
213 | - if (!iommu) { | |
214 | - ret = -ENOMEM; | |
215 | - goto error; | |
216 | - } | |
217 | + | |
218 | + iommu = drhd->iommu; | |
219 | ||
220 | ret = iommu_init_domains(iommu); | |
221 | if (ret) | |
222 | @@ -2349,6 +2346,9 @@ int __init intel_iommu_init(void) | |
223 | if (dmar_table_init()) | |
224 | return -ENODEV; | |
225 | ||
226 | + if (dmar_dev_scope_init()) | |
227 | + return -ENODEV; | |
228 | + | |
229 | iommu_init_mempool(); | |
230 | dmar_init_reserved_ranges(); | |
231 | ||
232 | --- a/drivers/pci/intel-iommu.h | |
233 | +++ b/drivers/pci/intel-iommu.h | |
234 | @@ -199,7 +199,7 @@ struct intel_iommu { | |
235 | ||
236 | extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); | |
237 | ||
238 | -extern struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd); | |
239 | +extern int alloc_iommu(struct dmar_drhd_unit *drhd); | |
240 | extern void free_iommu(struct intel_iommu *iommu); | |
241 | ||
242 | #endif | |
243 | --- a/include/linux/dmar.h | |
244 | +++ b/include/linux/dmar.h | |
245 | @@ -46,12 +46,14 @@ extern int intel_iommu_init(void); | |
246 | ||
247 | extern int dmar_table_init(void); | |
248 | extern int early_dmar_detect(void); | |
249 | +extern int dmar_dev_scope_init(void); | |
250 | ||
251 | extern struct list_head dmar_drhd_units; | |
252 | extern struct list_head dmar_rmrr_units; | |
253 | ||
254 | struct dmar_drhd_unit { | |
255 | struct list_head list; /* list of drhd units */ | |
256 | + struct acpi_dmar_header *hdr; /* ACPI header */ | |
257 | u64 reg_base_addr; /* register base address*/ | |
258 | struct pci_dev **devices; /* target device array */ | |
259 | int devices_cnt; /* target device count */ | |
260 | @@ -62,6 +64,7 @@ struct dmar_drhd_unit { | |
261 | ||
262 | struct dmar_rmrr_unit { | |
263 | struct list_head list; /* list of rmrr units */ | |
264 | + struct acpi_dmar_header *hdr; /* ACPI header */ | |
265 | u64 base_address; /* reserved base address*/ | |
266 | u64 end_address; /* reserved end address */ | |
267 | struct pci_dev **devices; /* target devices */ | |
268 | @@ -72,6 +75,8 @@ struct dmar_rmrr_unit { | |
269 | list_for_each_entry(drhd, &dmar_drhd_units, list) | |
270 | #define for_each_rmrr_units(rmrr) \ | |
271 | list_for_each_entry(rmrr, &dmar_rmrr_units, list) | |
272 | + | |
273 | +extern int alloc_iommu(struct dmar_drhd_unit *); | |
274 | #else | |
275 | static inline void detect_intel_iommu(void) | |
276 | { | |
277 | @@ -81,6 +86,9 @@ static inline int intel_iommu_init(void) | |
278 | { | |
279 | return -ENODEV; | |
280 | } | |
281 | - | |
282 | +static inline int dmar_table_init(void) | |
283 | +{ | |
284 | + return -ENODEV; | |
285 | +} | |
286 | #endif /* !CONFIG_DMAR */ | |
287 | #endif /* __DMAR_H__ */ |