aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/amd_iommu_init.c
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2008-06-26 15:27:47 -0400
committerIngo Molnar <mingo@elte.hu>2008-06-27 04:12:11 -0400
commit5d0c8e49f88b908a8fcc913c4b9843108ae8897b (patch)
treea51ebfd8c247b2d939457afb8c7f0361adf2bd41 /arch/x86/kernel/amd_iommu_init.c
parent3566b7786afd7c14c62726f359df3c827054670b (diff)
x86, AMD IOMMU: add functions for IOMMU hardware initialization from ACPI
This patch adds functions to initialize the IOMMU hardware with information from ACPI and PCI. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Cc: iommu@lists.linux-foundation.org Cc: bhavna.sarathy@amd.com Cc: Sebastian.Biemueller@amd.com Cc: robert.richter@amd.com Cc: joro@8bytes.org Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/amd_iommu_init.c')
-rw-r--r--arch/x86/kernel/amd_iommu_init.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 4c37abb3435b..8ec48f1f39d3 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -353,3 +353,128 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
353 } 353 }
354} 354}
355 355
356static void __init init_iommu_from_pci(struct amd_iommu *iommu)
357{
358 int bus = PCI_BUS(iommu->devid);
359 int dev = PCI_SLOT(iommu->devid);
360 int fn = PCI_FUNC(iommu->devid);
361 int cap_ptr = iommu->cap_ptr;
362 u32 range;
363
364 iommu->cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_CAP_HDR_OFFSET);
365
366 range = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET);
367 iommu->first_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_FD(range));
368 iommu->last_device = DEVID(MMIO_GET_BUS(range), MMIO_GET_LD(range));
369}
370
371static void __init init_iommu_from_acpi(struct amd_iommu *iommu,
372 struct ivhd_header *h)
373{
374 u8 *p = (u8 *)h;
375 u8 *end = p, flags = 0;
376 u16 dev_i, devid = 0, devid_start = 0, devid_to = 0;
377 u32 ext_flags = 0;
378 bool alias = 0;
379 struct ivhd_entry *e;
380
381 /*
382 * First set the recommended feature enable bits from ACPI
383 * into the IOMMU control registers
384 */
385 h->flags & IVHD_FLAG_HT_TUN_EN ?
386 iommu_feature_enable(iommu, CONTROL_HT_TUN_EN) :
387 iommu_feature_disable(iommu, CONTROL_HT_TUN_EN);
388
389 h->flags & IVHD_FLAG_PASSPW_EN ?
390 iommu_feature_enable(iommu, CONTROL_PASSPW_EN) :
391 iommu_feature_disable(iommu, CONTROL_PASSPW_EN);
392
393 h->flags & IVHD_FLAG_RESPASSPW_EN ?
394 iommu_feature_enable(iommu, CONTROL_RESPASSPW_EN) :
395 iommu_feature_disable(iommu, CONTROL_RESPASSPW_EN);
396
397 h->flags & IVHD_FLAG_ISOC_EN ?
398 iommu_feature_enable(iommu, CONTROL_ISOC_EN) :
399 iommu_feature_disable(iommu, CONTROL_ISOC_EN);
400
401 /*
402 * make IOMMU memory accesses cache coherent
403 */
404 iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
405
406 /*
407 * Done. Now parse the device entries
408 */
409 p += sizeof(struct ivhd_header);
410 end += h->length;
411
412 while (p < end) {
413 e = (struct ivhd_entry *)p;
414 switch (e->type) {
415 case IVHD_DEV_ALL:
416 for (dev_i = iommu->first_device;
417 dev_i <= iommu->last_device; ++dev_i)
418 set_dev_entry_from_acpi(dev_i, e->flags, 0);
419 break;
420 case IVHD_DEV_SELECT:
421 devid = e->devid;
422 set_dev_entry_from_acpi(devid, e->flags, 0);
423 break;
424 case IVHD_DEV_SELECT_RANGE_START:
425 devid_start = e->devid;
426 flags = e->flags;
427 ext_flags = 0;
428 alias = 0;
429 break;
430 case IVHD_DEV_ALIAS:
431 devid = e->devid;
432 devid_to = e->ext >> 8;
433 set_dev_entry_from_acpi(devid, e->flags, 0);
434 amd_iommu_alias_table[devid] = devid_to;
435 break;
436 case IVHD_DEV_ALIAS_RANGE:
437 devid_start = e->devid;
438 flags = e->flags;
439 devid_to = e->ext >> 8;
440 ext_flags = 0;
441 alias = 1;
442 break;
443 case IVHD_DEV_EXT_SELECT:
444 devid = e->devid;
445 set_dev_entry_from_acpi(devid, e->flags, e->ext);
446 break;
447 case IVHD_DEV_EXT_SELECT_RANGE:
448 devid_start = e->devid;
449 flags = e->flags;
450 ext_flags = e->ext;
451 alias = 0;
452 break;
453 case IVHD_DEV_RANGE_END:
454 devid = e->devid;
455 for (dev_i = devid_start; dev_i <= devid; ++dev_i) {
456 if (alias)
457 amd_iommu_alias_table[dev_i] = devid_to;
458 set_dev_entry_from_acpi(
459 amd_iommu_alias_table[dev_i],
460 flags, ext_flags);
461 }
462 break;
463 default:
464 break;
465 }
466
467 p += 0x04 << (e->type >> 6);
468 }
469}
470
471static int __init init_iommu_devices(struct amd_iommu *iommu)
472{
473 u16 i;
474
475 for (i = iommu->first_device; i <= iommu->last_device; ++i)
476 set_iommu_for_device(iommu, i);
477
478 return 0;
479}
480