diff options
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r-- | drivers/pci/dmar.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index f941f609dbf3..c00e387f5b75 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c | |||
@@ -19,9 +19,11 @@ | |||
19 | * Author: Shaohua Li <shaohua.li@intel.com> | 19 | * Author: Shaohua Li <shaohua.li@intel.com> |
20 | * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> | 20 | * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> |
21 | * | 21 | * |
22 | * This file implements early detection/parsing of DMA Remapping Devices | 22 | * This file implements early detection/parsing of Remapping Devices |
23 | * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI | 23 | * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI |
24 | * tables. | 24 | * tables. |
25 | * | ||
26 | * These routines are used by both DMA-remapping and Interrupt-remapping | ||
25 | */ | 27 | */ |
26 | 28 | ||
27 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
@@ -300,6 +302,37 @@ parse_dmar_table(void) | |||
300 | return ret; | 302 | return ret; |
301 | } | 303 | } |
302 | 304 | ||
305 | int dmar_pci_device_match(struct pci_dev *devices[], int cnt, | ||
306 | struct pci_dev *dev) | ||
307 | { | ||
308 | int index; | ||
309 | |||
310 | while (dev) { | ||
311 | for (index = 0; index < cnt; index++) | ||
312 | if (dev == devices[index]) | ||
313 | return 1; | ||
314 | |||
315 | /* Check our parent */ | ||
316 | dev = dev->bus->self; | ||
317 | } | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | struct dmar_drhd_unit * | ||
323 | dmar_find_matched_drhd_unit(struct pci_dev *dev) | ||
324 | { | ||
325 | struct dmar_drhd_unit *drhd = NULL; | ||
326 | |||
327 | list_for_each_entry(drhd, &dmar_drhd_units, list) { | ||
328 | if (drhd->include_all || dmar_pci_device_match(drhd->devices, | ||
329 | drhd->devices_cnt, dev)) | ||
330 | return drhd; | ||
331 | } | ||
332 | |||
333 | return NULL; | ||
334 | } | ||
335 | |||
303 | 336 | ||
304 | int __init dmar_table_init(void) | 337 | int __init dmar_table_init(void) |
305 | { | 338 | { |
@@ -343,3 +376,58 @@ int __init early_dmar_detect(void) | |||
343 | 376 | ||
344 | return (ACPI_SUCCESS(status) ? 1 : 0); | 377 | return (ACPI_SUCCESS(status) ? 1 : 0); |
345 | } | 378 | } |
379 | |||
380 | struct intel_iommu *alloc_iommu(struct intel_iommu *iommu, | ||
381 | struct dmar_drhd_unit *drhd) | ||
382 | { | ||
383 | int map_size; | ||
384 | u32 ver; | ||
385 | |||
386 | iommu->reg = ioremap(drhd->reg_base_addr, PAGE_SIZE_4K); | ||
387 | if (!iommu->reg) { | ||
388 | printk(KERN_ERR "IOMMU: can't map the region\n"); | ||
389 | goto error; | ||
390 | } | ||
391 | iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG); | ||
392 | iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG); | ||
393 | |||
394 | /* the registers might be more than one page */ | ||
395 | map_size = max_t(int, ecap_max_iotlb_offset(iommu->ecap), | ||
396 | cap_max_fault_reg_offset(iommu->cap)); | ||
397 | map_size = PAGE_ALIGN_4K(map_size); | ||
398 | if (map_size > PAGE_SIZE_4K) { | ||
399 | iounmap(iommu->reg); | ||
400 | iommu->reg = ioremap(drhd->reg_base_addr, map_size); | ||
401 | if (!iommu->reg) { | ||
402 | printk(KERN_ERR "IOMMU: can't map the region\n"); | ||
403 | goto error; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | ver = readl(iommu->reg + DMAR_VER_REG); | ||
408 | pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n", | ||
409 | drhd->reg_base_addr, DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver), | ||
410 | iommu->cap, iommu->ecap); | ||
411 | |||
412 | spin_lock_init(&iommu->register_lock); | ||
413 | |||
414 | drhd->iommu = iommu; | ||
415 | return iommu; | ||
416 | error: | ||
417 | kfree(iommu); | ||
418 | return NULL; | ||
419 | } | ||
420 | |||
421 | void free_iommu(struct intel_iommu *iommu) | ||
422 | { | ||
423 | if (!iommu) | ||
424 | return; | ||
425 | |||
426 | #ifdef CONFIG_DMAR | ||
427 | free_dmar_iommu(iommu); | ||
428 | #endif | ||
429 | |||
430 | if (iommu->reg) | ||
431 | iounmap(iommu->reg); | ||
432 | kfree(iommu); | ||
433 | } | ||