diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-11-10 09:41:40 -0500 |
---|---|---|
committer | Joerg Roedel <joerg.roedel@amd.com> | 2011-12-12 08:54:37 -0500 |
commit | 1a29ac014a68e5da8f96d5d8d142b5956eb00b7c (patch) | |
tree | c0b88ba4f1771eb89e8252bdc0542f60e1e5da03 /drivers/iommu | |
parent | 62f71abbc64d686064a4caa10a3249c26776995e (diff) |
iommu/amd: Setup PPR log when supported by IOMMU
Allocate and enable a log buffer for peripheral page faults
when the IOMMU supports this feature.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/amd_iommu_init.c | 51 | ||||
-rw-r--r-- | drivers/iommu/amd_iommu_types.h | 14 |
2 files changed, 65 insertions, 0 deletions
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index fb4afd6d357d..60716cefa7af 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c | |||
@@ -583,6 +583,46 @@ static void __init free_event_buffer(struct amd_iommu *iommu) | |||
583 | free_pages((unsigned long)iommu->evt_buf, get_order(EVT_BUFFER_SIZE)); | 583 | free_pages((unsigned long)iommu->evt_buf, get_order(EVT_BUFFER_SIZE)); |
584 | } | 584 | } |
585 | 585 | ||
586 | /* allocates the memory where the IOMMU will log its events to */ | ||
587 | static u8 * __init alloc_ppr_log(struct amd_iommu *iommu) | ||
588 | { | ||
589 | iommu->ppr_log = (u8 *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
590 | get_order(PPR_LOG_SIZE)); | ||
591 | |||
592 | if (iommu->ppr_log == NULL) | ||
593 | return NULL; | ||
594 | |||
595 | return iommu->ppr_log; | ||
596 | } | ||
597 | |||
598 | static void iommu_enable_ppr_log(struct amd_iommu *iommu) | ||
599 | { | ||
600 | u64 entry; | ||
601 | |||
602 | if (iommu->ppr_log == NULL) | ||
603 | return; | ||
604 | |||
605 | entry = (u64)virt_to_phys(iommu->ppr_log) | PPR_LOG_SIZE_512; | ||
606 | |||
607 | memcpy_toio(iommu->mmio_base + MMIO_PPR_LOG_OFFSET, | ||
608 | &entry, sizeof(entry)); | ||
609 | |||
610 | /* set head and tail to zero manually */ | ||
611 | writel(0x00, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); | ||
612 | writel(0x00, iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); | ||
613 | |||
614 | iommu_feature_enable(iommu, CONTROL_PPFLOG_EN); | ||
615 | iommu_feature_enable(iommu, CONTROL_PPR_EN); | ||
616 | } | ||
617 | |||
618 | static void __init free_ppr_log(struct amd_iommu *iommu) | ||
619 | { | ||
620 | if (iommu->ppr_log == NULL) | ||
621 | return; | ||
622 | |||
623 | free_pages((unsigned long)iommu->ppr_log, get_order(PPR_LOG_SIZE)); | ||
624 | } | ||
625 | |||
586 | /* sets a specific bit in the device table entry. */ | 626 | /* sets a specific bit in the device table entry. */ |
587 | static void set_dev_entry_bit(u16 devid, u8 bit) | 627 | static void set_dev_entry_bit(u16 devid, u8 bit) |
588 | { | 628 | { |
@@ -914,6 +954,7 @@ static void __init free_iommu_one(struct amd_iommu *iommu) | |||
914 | { | 954 | { |
915 | free_command_buffer(iommu); | 955 | free_command_buffer(iommu); |
916 | free_event_buffer(iommu); | 956 | free_event_buffer(iommu); |
957 | free_ppr_log(iommu); | ||
917 | iommu_unmap_mmio_space(iommu); | 958 | iommu_unmap_mmio_space(iommu); |
918 | } | 959 | } |
919 | 960 | ||
@@ -977,6 +1018,12 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) | |||
977 | init_iommu_from_acpi(iommu, h); | 1018 | init_iommu_from_acpi(iommu, h); |
978 | init_iommu_devices(iommu); | 1019 | init_iommu_devices(iommu); |
979 | 1020 | ||
1021 | if (iommu_feature(iommu, FEATURE_PPR)) { | ||
1022 | iommu->ppr_log = alloc_ppr_log(iommu); | ||
1023 | if (!iommu->ppr_log) | ||
1024 | return -ENOMEM; | ||
1025 | } | ||
1026 | |||
980 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) | 1027 | if (iommu->cap & (1UL << IOMMU_CAP_NPCACHE)) |
981 | amd_iommu_np_cache = true; | 1028 | amd_iommu_np_cache = true; |
982 | 1029 | ||
@@ -1063,6 +1110,9 @@ static int iommu_setup_msi(struct amd_iommu *iommu) | |||
1063 | iommu->int_enabled = true; | 1110 | iommu->int_enabled = true; |
1064 | iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); | 1111 | iommu_feature_enable(iommu, CONTROL_EVT_INT_EN); |
1065 | 1112 | ||
1113 | if (iommu->ppr_log != NULL) | ||
1114 | iommu_feature_enable(iommu, CONTROL_PPFINT_EN); | ||
1115 | |||
1066 | return 0; | 1116 | return 0; |
1067 | } | 1117 | } |
1068 | 1118 | ||
@@ -1287,6 +1337,7 @@ static void enable_iommus(void) | |||
1287 | iommu_set_device_table(iommu); | 1337 | iommu_set_device_table(iommu); |
1288 | iommu_enable_command_buffer(iommu); | 1338 | iommu_enable_command_buffer(iommu); |
1289 | iommu_enable_event_buffer(iommu); | 1339 | iommu_enable_event_buffer(iommu); |
1340 | iommu_enable_ppr_log(iommu); | ||
1290 | iommu_set_exclusion_range(iommu); | 1341 | iommu_set_exclusion_range(iommu); |
1291 | iommu_init_msi(iommu); | 1342 | iommu_init_msi(iommu); |
1292 | iommu_enable(iommu); | 1343 | iommu_enable(iommu); |
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 0d984ca925be..4dc230904fe9 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h | |||
@@ -69,11 +69,14 @@ | |||
69 | #define MMIO_EXCL_BASE_OFFSET 0x0020 | 69 | #define MMIO_EXCL_BASE_OFFSET 0x0020 |
70 | #define MMIO_EXCL_LIMIT_OFFSET 0x0028 | 70 | #define MMIO_EXCL_LIMIT_OFFSET 0x0028 |
71 | #define MMIO_EXT_FEATURES 0x0030 | 71 | #define MMIO_EXT_FEATURES 0x0030 |
72 | #define MMIO_PPR_LOG_OFFSET 0x0038 | ||
72 | #define MMIO_CMD_HEAD_OFFSET 0x2000 | 73 | #define MMIO_CMD_HEAD_OFFSET 0x2000 |
73 | #define MMIO_CMD_TAIL_OFFSET 0x2008 | 74 | #define MMIO_CMD_TAIL_OFFSET 0x2008 |
74 | #define MMIO_EVT_HEAD_OFFSET 0x2010 | 75 | #define MMIO_EVT_HEAD_OFFSET 0x2010 |
75 | #define MMIO_EVT_TAIL_OFFSET 0x2018 | 76 | #define MMIO_EVT_TAIL_OFFSET 0x2018 |
76 | #define MMIO_STATUS_OFFSET 0x2020 | 77 | #define MMIO_STATUS_OFFSET 0x2020 |
78 | #define MMIO_PPR_HEAD_OFFSET 0x2030 | ||
79 | #define MMIO_PPR_TAIL_OFFSET 0x2038 | ||
77 | 80 | ||
78 | 81 | ||
79 | /* Extended Feature Bits */ | 82 | /* Extended Feature Bits */ |
@@ -125,6 +128,7 @@ | |||
125 | #define CONTROL_CMDBUF_EN 0x0cULL | 128 | #define CONTROL_CMDBUF_EN 0x0cULL |
126 | #define CONTROL_PPFLOG_EN 0x0dULL | 129 | #define CONTROL_PPFLOG_EN 0x0dULL |
127 | #define CONTROL_PPFINT_EN 0x0eULL | 130 | #define CONTROL_PPFINT_EN 0x0eULL |
131 | #define CONTROL_PPR_EN 0x0fULL | ||
128 | 132 | ||
129 | /* command specific defines */ | 133 | /* command specific defines */ |
130 | #define CMD_COMPL_WAIT 0x01 | 134 | #define CMD_COMPL_WAIT 0x01 |
@@ -168,6 +172,13 @@ | |||
168 | #define EVT_BUFFER_SIZE 8192 /* 512 entries */ | 172 | #define EVT_BUFFER_SIZE 8192 /* 512 entries */ |
169 | #define EVT_LEN_MASK (0x9ULL << 56) | 173 | #define EVT_LEN_MASK (0x9ULL << 56) |
170 | 174 | ||
175 | /* Constants for PPR Log handling */ | ||
176 | #define PPR_LOG_ENTRIES 512 | ||
177 | #define PPR_LOG_SIZE_SHIFT 56 | ||
178 | #define PPR_LOG_SIZE_512 (0x9ULL << PPR_LOG_SIZE_SHIFT) | ||
179 | #define PPR_ENTRY_SIZE 16 | ||
180 | #define PPR_LOG_SIZE (PPR_ENTRY_SIZE * PPR_LOG_ENTRIES) | ||
181 | |||
171 | #define PAGE_MODE_NONE 0x00 | 182 | #define PAGE_MODE_NONE 0x00 |
172 | #define PAGE_MODE_1_LEVEL 0x01 | 183 | #define PAGE_MODE_1_LEVEL 0x01 |
173 | #define PAGE_MODE_2_LEVEL 0x02 | 184 | #define PAGE_MODE_2_LEVEL 0x02 |
@@ -434,6 +445,9 @@ struct amd_iommu { | |||
434 | /* MSI number for event interrupt */ | 445 | /* MSI number for event interrupt */ |
435 | u16 evt_msi_num; | 446 | u16 evt_msi_num; |
436 | 447 | ||
448 | /* Base of the PPR log, if present */ | ||
449 | u8 *ppr_log; | ||
450 | |||
437 | /* true if interrupts for this IOMMU are already enabled */ | 451 | /* true if interrupts for this IOMMU are already enabled */ |
438 | bool int_enabled; | 452 | bool int_enabled; |
439 | 453 | ||