diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/dmar.c | 89 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.c | 10 | ||||
-rw-r--r-- | drivers/pci/intel-iommu.h | 2 |
3 files changed, 79 insertions, 22 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 1a59423a8eda..158bc5bfcf75 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -174,19 +174,37 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) | |||
174 | struct acpi_dmar_hardware_unit *drhd; | 174 | struct acpi_dmar_hardware_unit *drhd; |
175 | struct dmar_drhd_unit *dmaru; | 175 | struct dmar_drhd_unit *dmaru; |
176 | int ret = 0; | 176 | int ret = 0; |
177 | static int include_all; | ||
178 | 177 | ||
179 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); | 178 | dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL); |
180 | if (!dmaru) | 179 | if (!dmaru) |
181 | return -ENOMEM; | 180 | return -ENOMEM; |
182 | 181 | ||
182 | dmaru->hdr = header; | ||
183 | drhd = (struct acpi_dmar_hardware_unit *)header; | 183 | drhd = (struct acpi_dmar_hardware_unit *)header; |
184 | dmaru->reg_base_addr = drhd->address; | 184 | dmaru->reg_base_addr = drhd->address; |
185 | dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ | 185 | dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */ |
186 | 186 | ||
187 | ret = alloc_iommu(dmaru); | ||
188 | if (ret) { | ||
189 | kfree(dmaru); | ||
190 | return ret; | ||
191 | } | ||
192 | dmar_register_drhd_unit(dmaru); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int __init | ||
197 | dmar_parse_dev(struct dmar_drhd_unit *dmaru) | ||
198 | { | ||
199 | struct acpi_dmar_hardware_unit *drhd; | ||
200 | static int include_all; | ||
201 | int ret; | ||
202 | |||
203 | drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr; | ||
204 | |||
187 | if (!dmaru->include_all) | 205 | if (!dmaru->include_all) |
188 | ret = dmar_parse_dev_scope((void *)(drhd + 1), | 206 | ret = dmar_parse_dev_scope((void *)(drhd + 1), |
189 | ((void *)drhd) + header->length, | 207 | ((void *)drhd) + drhd->header.length, |
190 | &dmaru->devices_cnt, &dmaru->devices, | 208 | &dmaru->devices_cnt, &dmaru->devices, |
191 | drhd->segment); | 209 | drhd->segment); |
192 | else { | 210 | else { |
@@ -199,10 +217,10 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header) | |||
199 | include_all = 1; | 217 | include_all = 1; |
200 | } | 218 | } |
201 | 219 | ||
202 | if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) | 220 | if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all)) { |
221 | list_del(&dmaru->list); | ||
203 | kfree(dmaru); | 222 | kfree(dmaru); |
204 | else | 223 | } |
205 | dmar_register_drhd_unit(dmaru); | ||
206 | return ret; | 224 | return ret; |
207 | } | 225 | } |
208 | 226 | ||
@@ -211,23 +229,35 @@ dmar_parse_one_rmrr(struct acpi_dmar_header *header) | |||
211 | { | 229 | { |
212 | struct acpi_dmar_reserved_memory *rmrr; | 230 | struct acpi_dmar_reserved_memory *rmrr; |
213 | struct dmar_rmrr_unit *rmrru; | 231 | struct dmar_rmrr_unit *rmrru; |
214 | int ret = 0; | ||
215 | 232 | ||
216 | rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); | 233 | rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); |
217 | if (!rmrru) | 234 | if (!rmrru) |
218 | return -ENOMEM; | 235 | return -ENOMEM; |
219 | 236 | ||
237 | rmrru->hdr = header; | ||
220 | rmrr = (struct acpi_dmar_reserved_memory *)header; | 238 | rmrr = (struct acpi_dmar_reserved_memory *)header; |
221 | rmrru->base_address = rmrr->base_address; | 239 | rmrru->base_address = rmrr->base_address; |
222 | rmrru->end_address = rmrr->end_address; | 240 | rmrru->end_address = rmrr->end_address; |
241 | |||
242 | dmar_register_rmrr_unit(rmrru); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static int __init | ||
247 | rmrr_parse_dev(struct dmar_rmrr_unit *rmrru) | ||
248 | { | ||
249 | struct acpi_dmar_reserved_memory *rmrr; | ||
250 | int ret; | ||
251 | |||
252 | rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr; | ||
223 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), | 253 | ret = dmar_parse_dev_scope((void *)(rmrr + 1), |
224 | ((void *)rmrr) + header->length, | 254 | ((void *)rmrr) + rmrr->header.length, |
225 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); | 255 | &rmrru->devices_cnt, &rmrru->devices, rmrr->segment); |
226 | 256 | ||
227 | if (ret || (rmrru->devices_cnt == 0)) | 257 | if (ret || (rmrru->devices_cnt == 0)) { |
258 | list_del(&rmrru->list); | ||
228 | kfree(rmrru); | 259 | kfree(rmrru); |
229 | else | 260 | } |
230 | dmar_register_rmrr_unit(rmrru); | ||
231 | return ret; | 261 | return ret; |
232 | } | 262 | } |
233 | 263 | ||
@@ -333,15 +363,42 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev) | |||
333 | return NULL; | 363 | return NULL; |
334 | } | 364 | } |
335 | 365 | ||
366 | int __init dmar_dev_scope_init(void) | ||
367 | { | ||
368 | struct dmar_drhd_unit *drhd; | ||
369 | struct dmar_rmrr_unit *rmrr; | ||
370 | int ret = -ENODEV; | ||
371 | |||
372 | for_each_drhd_unit(drhd) { | ||
373 | ret = dmar_parse_dev(drhd); | ||
374 | if (ret) | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | for_each_rmrr_units(rmrr) { | ||
379 | ret = rmrr_parse_dev(rmrr); | ||
380 | if (ret) | ||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | return ret; | ||
385 | } | ||
386 | |||
336 | 387 | ||
337 | int __init dmar_table_init(void) | 388 | int __init dmar_table_init(void) |
338 | { | 389 | { |
339 | 390 | static int dmar_table_initialized; | |
340 | int ret; | 391 | int ret; |
341 | 392 | ||
393 | if (dmar_table_initialized) | ||
394 | return 0; | ||
395 | |||
396 | dmar_table_initialized = 1; | ||
397 | |||
342 | ret = parse_dmar_table(); | 398 | ret = parse_dmar_table(); |
343 | if (ret) { | 399 | if (ret) { |
344 | printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); | 400 | if (ret != -ENODEV) |
401 | printk(KERN_INFO PREFIX "parse DMAR table failure.\n"); | ||
345 | return ret; | 402 | return ret; |
346 | } | 403 | } |
347 | 404 | ||
@@ -377,7 +434,7 @@ int __init early_dmar_detect(void) | |||
377 | return (ACPI_SUCCESS(status) ? 1 : 0); | 434 | return (ACPI_SUCCESS(status) ? 1 : 0); |
378 | } | 435 | } |
379 | 436 | ||
380 | struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) | 437 | int alloc_iommu(struct dmar_drhd_unit *drhd) |
381 | { | 438 | { |
382 | struct intel_iommu *iommu; | 439 | struct intel_iommu *iommu; |
383 | int map_size; | 440 | int map_size; |
@@ -386,7 +443,7 @@ struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) | |||
386 | 443 | ||
387 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 444 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); |
388 | if (!iommu) | 445 | if (!iommu) |
389 | return NULL; | 446 | return -ENOMEM; |
390 | 447 | ||
391 | iommu->seq_id = iommu_allocated++; | 448 | iommu->seq_id = iommu_allocated++; |
392 | 449 | ||
@@ -419,10 +476,10 @@ struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd) | |||
419 | spin_lock_init(&iommu->register_lock); | 476 | spin_lock_init(&iommu->register_lock); |
420 | 477 | ||
421 | drhd->iommu = iommu; | 478 | drhd->iommu = iommu; |
422 | return iommu; | 479 | return 0; |
423 | error: | 480 | error: |
424 | kfree(iommu); | 481 | kfree(iommu); |
425 | return NULL; | 482 | return -1; |
426 | } | 483 | } |
427 | 484 | ||
428 | void free_iommu(struct intel_iommu *iommu) | 485 | void free_iommu(struct intel_iommu *iommu) |
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4d59a6a1f4dd..218a1f357b4d 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c | |||
@@ -1665,11 +1665,8 @@ int __init init_dmars(void) | |||
1665 | for_each_drhd_unit(drhd) { | 1665 | for_each_drhd_unit(drhd) { |
1666 | if (drhd->ignored) | 1666 | if (drhd->ignored) |
1667 | continue; | 1667 | continue; |
1668 | iommu = alloc_iommu(drhd); | 1668 | |
1669 | if (!iommu) { | 1669 | iommu = drhd->iommu; |
1670 | ret = -ENOMEM; | ||
1671 | goto error; | ||
1672 | } | ||
1673 | 1670 | ||
1674 | ret = iommu_init_domains(iommu); | 1671 | ret = iommu_init_domains(iommu); |
1675 | if (ret) | 1672 | if (ret) |
@@ -2324,6 +2321,9 @@ int __init intel_iommu_init(void) | |||
2324 | if (dmar_table_init()) | 2321 | if (dmar_table_init()) |
2325 | return -ENODEV; | 2322 | return -ENODEV; |
2326 | 2323 | ||
2324 | if (dmar_dev_scope_init()) | ||
2325 | return -ENODEV; | ||
2326 | |||
2327 | iommu_init_mempool(); | 2327 | iommu_init_mempool(); |
2328 | dmar_init_reserved_ranges(); | 2328 | dmar_init_reserved_ranges(); |
2329 | 2329 | ||
diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h index 75c63f65b3f5..371e3b9caf32 100644 --- a/drivers/pci/intel-iommu.h +++ b/drivers/pci/intel-iommu.h | |||
@@ -199,7 +199,7 @@ struct intel_iommu { | |||
199 | 199 | ||
200 | extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); | 200 | extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev); |
201 | 201 | ||
202 | extern struct intel_iommu *alloc_iommu(struct dmar_drhd_unit *drhd); | 202 | extern int alloc_iommu(struct dmar_drhd_unit *drhd); |
203 | extern void free_iommu(struct intel_iommu *iommu); | 203 | extern void free_iommu(struct intel_iommu *iommu); |
204 | 204 | ||
205 | #endif | 205 | #endif |