diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2008-06-26 15:27:41 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-27 04:12:08 -0400 |
commit | 3e8064ba59128bcb1405079a0789b27b356832b9 (patch) | |
tree | 63d80264b10c69a606cce9f7dd2c1c9a243b8d76 | |
parent | 928abd2545fe367ea3ff3cb8a5076e1d6d2a9574 (diff) |
x86, AMD IOMMU: add functions to find last possible PCI device for IOMMU
This patch adds functions to find the last PCI bus/device/function the IOMMU
driver has to handle. This information is used later to allocate the memory for
the data structures.
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>
-rw-r--r-- | arch/x86/kernel/amd_iommu_init.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c index 0ad8cf9e7ba2..ee0b2da027bc 100644 --- a/arch/x86/kernel/amd_iommu_init.c +++ b/arch/x86/kernel/amd_iommu_init.c | |||
@@ -116,3 +116,82 @@ unsigned long *amd_iommu_pd_alloc_bitmap; | |||
116 | static u32 dev_table_size; | 116 | static u32 dev_table_size; |
117 | static u32 alias_table_size; | 117 | static u32 alias_table_size; |
118 | static u32 rlookup_table_size; | 118 | static u32 rlookup_table_size; |
119 | |||
120 | static int __init find_last_devid_on_pci(int bus, int dev, int fn, int cap_ptr) | ||
121 | { | ||
122 | u32 cap; | ||
123 | |||
124 | cap = read_pci_config(bus, dev, fn, cap_ptr+MMIO_RANGE_OFFSET); | ||
125 | UPDATE_LAST_BDF(DEVID(MMIO_GET_BUS(cap), MMIO_GET_LD(cap))); | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int __init find_last_devid_from_ivhd(struct ivhd_header *h) | ||
131 | { | ||
132 | u8 *p = (void *)h, *end = (void *)h; | ||
133 | struct ivhd_entry *dev; | ||
134 | |||
135 | p += sizeof(*h); | ||
136 | end += h->length; | ||
137 | |||
138 | find_last_devid_on_pci(PCI_BUS(h->devid), | ||
139 | PCI_SLOT(h->devid), | ||
140 | PCI_FUNC(h->devid), | ||
141 | h->cap_ptr); | ||
142 | |||
143 | while (p < end) { | ||
144 | dev = (struct ivhd_entry *)p; | ||
145 | switch (dev->type) { | ||
146 | case IVHD_DEV_SELECT: | ||
147 | case IVHD_DEV_RANGE_END: | ||
148 | case IVHD_DEV_ALIAS: | ||
149 | case IVHD_DEV_EXT_SELECT: | ||
150 | UPDATE_LAST_BDF(dev->devid); | ||
151 | break; | ||
152 | default: | ||
153 | break; | ||
154 | } | ||
155 | p += 0x04 << (*p >> 6); | ||
156 | } | ||
157 | |||
158 | WARN_ON(p != end); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int __init find_last_devid_acpi(struct acpi_table_header *table) | ||
164 | { | ||
165 | int i; | ||
166 | u8 checksum = 0, *p = (u8 *)table, *end = (u8 *)table; | ||
167 | struct ivhd_header *h; | ||
168 | |||
169 | /* | ||
170 | * Validate checksum here so we don't need to do it when | ||
171 | * we actually parse the table | ||
172 | */ | ||
173 | for (i = 0; i < table->length; ++i) | ||
174 | checksum += p[i]; | ||
175 | if (checksum != 0) | ||
176 | /* ACPI table corrupt */ | ||
177 | return -ENODEV; | ||
178 | |||
179 | p += IVRS_HEADER_LENGTH; | ||
180 | |||
181 | end += table->length; | ||
182 | while (p < end) { | ||
183 | h = (struct ivhd_header *)p; | ||
184 | switch (h->type) { | ||
185 | case ACPI_IVHD_TYPE: | ||
186 | find_last_devid_from_ivhd(h); | ||
187 | break; | ||
188 | default: | ||
189 | break; | ||
190 | } | ||
191 | p += h->length; | ||
192 | } | ||
193 | WARN_ON(p != end); | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||