aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/dmar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/dmar.c')
-rw-r--r--drivers/pci/dmar.c90
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
305int 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
322struct dmar_drhd_unit *
323dmar_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
304int __init dmar_table_init(void) 337int __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
380struct 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;
416error:
417 kfree(iommu);
418 return NULL;
419}
420
421void 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}