ia64/xen-unstable

view xen/drivers/passthrough/amd/iommu_detect.c @ 17491:84b5dee690f5

AMD IOV: Fix xen boot on non-iommu systems.
Signed-off-by: Wei Wang <wei.wang2@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Apr 21 14:59:25 2008 +0100 (2008-04-21)
parents e823b22c6017
children 8bced3d8a907
line source
1 /*
2 * Copyright (C) 2007 Advanced Micro Devices, Inc.
3 * Author: Leo Duran <leo.duran@amd.com>
4 * Author: Wei Wang <wei.wang2@amd.com> - adapted to xen
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 #include <xen/config.h>
22 #include <xen/errno.h>
23 #include <xen/iommu.h>
24 #include <xen/pci.h>
25 #include <asm/amd-iommu.h>
26 #include <asm/hvm/svm/amd-iommu-proto.h>
27 #include "../pci_regs.h"
29 static int __init valid_bridge_bus_config(
30 int bus, int dev, int func, int *sec_bus, int *sub_bus)
31 {
32 int pri_bus;
34 pri_bus = pci_conf_read8(bus, dev, func, PCI_PRIMARY_BUS);
35 *sec_bus = pci_conf_read8(bus, dev, func, PCI_SECONDARY_BUS);
36 *sub_bus = pci_conf_read8(bus, dev, func, PCI_SUBORDINATE_BUS);
38 return ((pri_bus == bus) && (*sec_bus > bus) && (*sub_bus >= *sec_bus));
39 }
41 int __init get_iommu_last_downstream_bus(struct amd_iommu *iommu)
42 {
43 int bus, dev, func;
44 int devfn, hdr_type;
45 int sec_bus, sub_bus;
46 int multi_func;
48 bus = iommu->last_downstream_bus = iommu->root_bus;
49 iommu->downstream_bus_present[bus] = 1;
50 dev = PCI_SLOT(iommu->first_devfn);
51 multi_func = PCI_FUNC(iommu->first_devfn) > 0;
52 for ( devfn = iommu->first_devfn; devfn <= iommu->last_devfn; devfn++ )
53 {
54 /* skipping to next device#? */
55 if ( dev != PCI_SLOT(devfn) )
56 {
57 dev = PCI_SLOT(devfn);
58 multi_func = 0;
59 }
60 func = PCI_FUNC(devfn);
62 if ( !VALID_PCI_VENDOR_ID(pci_conf_read16(bus, dev, func,
63 PCI_VENDOR_ID)) )
64 continue;
66 hdr_type = pci_conf_read8(bus, dev, func, PCI_HEADER_TYPE);
67 if ( func == 0 )
68 multi_func = IS_PCI_MULTI_FUNCTION(hdr_type);
70 if ( (func == 0 || multi_func) &&
71 IS_PCI_TYPE1_HEADER(hdr_type) )
72 {
73 if ( !valid_bridge_bus_config(bus, dev, func,
74 &sec_bus, &sub_bus) )
75 return -ENODEV;
77 if ( sub_bus > iommu->last_downstream_bus )
78 iommu->last_downstream_bus = sub_bus;
79 do {
80 iommu->downstream_bus_present[sec_bus] = 1;
81 } while ( sec_bus++ < sub_bus );
82 }
83 }
85 return 0;
86 }
88 static int __init get_iommu_msi_capabilities(u8 bus, u8 dev, u8 func,
89 struct amd_iommu *iommu)
90 {
91 int cap_ptr, cap_id;
92 u32 cap_header;
93 u16 control;
94 int count = 0;
96 cap_ptr = pci_conf_read8(bus, dev, func,
97 PCI_CAPABILITY_LIST);
99 while ( cap_ptr >= PCI_MIN_CAP_OFFSET &&
100 count < PCI_MAX_CAP_BLOCKS )
101 {
102 cap_ptr &= PCI_CAP_PTR_MASK;
103 cap_header = pci_conf_read32(bus, dev, func, cap_ptr);
104 cap_id = get_field_from_reg_u32(cap_header,
105 PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
107 if ( cap_id == PCI_CAP_ID_MSI )
108 {
109 iommu->msi_cap = cap_ptr;
110 break;
111 }
112 cap_ptr = get_field_from_reg_u32(cap_header,
113 PCI_CAP_NEXT_PTR_MASK, PCI_CAP_NEXT_PTR_SHIFT);
114 count++;
115 }
117 if ( !iommu->msi_cap )
118 return -ENODEV;
120 amd_iov_info("Found MSI capability block \n");
121 control = pci_conf_read16(bus, dev, func,
122 iommu->msi_cap + PCI_MSI_FLAGS);
123 iommu->maskbit = control & PCI_MSI_FLAGS_MASKBIT;
124 return 0;
125 }
127 int __init get_iommu_capabilities(u8 bus, u8 dev, u8 func, u8 cap_ptr,
128 struct amd_iommu *iommu)
129 {
130 u32 cap_header, cap_range, misc_info;
131 u64 mmio_bar;
133 mmio_bar = (u64)pci_conf_read32(
134 bus, dev, func, cap_ptr + PCI_CAP_MMIO_BAR_HIGH_OFFSET) << 32;
135 mmio_bar |= pci_conf_read32(bus, dev, func,
136 cap_ptr + PCI_CAP_MMIO_BAR_LOW_OFFSET);
137 iommu->mmio_base_phys = mmio_bar & (u64)~0x3FFF;
139 if ( ((mmio_bar & 0x1) == 0) || (iommu->mmio_base_phys == 0) )
140 {
141 amd_iov_error("Invalid MMIO_BAR = 0x%"PRIx64"\n", mmio_bar);
142 return -ENODEV;
143 }
145 iommu->bdf = (bus << 8) | PCI_DEVFN(dev, func);
146 iommu->cap_offset = cap_ptr;
148 cap_header = pci_conf_read32(bus, dev, func, cap_ptr);
149 iommu->revision = get_field_from_reg_u32(
150 cap_header, PCI_CAP_REV_MASK, PCI_CAP_REV_SHIFT);
151 iommu->iotlb_support = get_field_from_reg_u32(
152 cap_header, PCI_CAP_IOTLB_MASK, PCI_CAP_IOTLB_SHIFT);
153 iommu->ht_tunnel_support = get_field_from_reg_u32(
154 cap_header, PCI_CAP_HT_TUNNEL_MASK, PCI_CAP_HT_TUNNEL_SHIFT);
155 iommu->pte_not_present_cached = get_field_from_reg_u32(
156 cap_header, PCI_CAP_NP_CACHE_MASK, PCI_CAP_NP_CACHE_SHIFT);
158 cap_range = pci_conf_read32(bus, dev, func,
159 cap_ptr + PCI_CAP_RANGE_OFFSET);
160 iommu->unit_id = get_field_from_reg_u32(
161 cap_range, PCI_CAP_UNIT_ID_MASK, PCI_CAP_UNIT_ID_SHIFT);
162 iommu->root_bus = get_field_from_reg_u32(
163 cap_range, PCI_CAP_BUS_NUMBER_MASK, PCI_CAP_BUS_NUMBER_SHIFT);
164 iommu->first_devfn = get_field_from_reg_u32(
165 cap_range, PCI_CAP_FIRST_DEVICE_MASK, PCI_CAP_FIRST_DEVICE_SHIFT);
166 iommu->last_devfn = get_field_from_reg_u32(
167 cap_range, PCI_CAP_LAST_DEVICE_MASK, PCI_CAP_LAST_DEVICE_SHIFT);
169 misc_info = pci_conf_read32(bus, dev, func,
170 cap_ptr + PCI_MISC_INFO_OFFSET);
171 iommu->msi_number = get_field_from_reg_u32(
172 misc_info, PCI_CAP_MSI_NUMBER_MASK, PCI_CAP_MSI_NUMBER_SHIFT);
174 get_iommu_msi_capabilities(bus, dev, func, iommu);
176 return 0;
177 }
179 static int __init scan_caps_for_iommu(
180 int bus, int dev, int func,
181 iommu_detect_callback_ptr_t iommu_detect_callback)
182 {
183 int cap_ptr, cap_id, cap_type;
184 u32 cap_header;
185 int count, error = 0;
187 count = 0;
188 cap_ptr = pci_conf_read8(bus, dev, func, PCI_CAPABILITY_LIST);
189 while ( (cap_ptr >= PCI_MIN_CAP_OFFSET) &&
190 (count < PCI_MAX_CAP_BLOCKS) &&
191 !error )
192 {
193 cap_ptr &= PCI_CAP_PTR_MASK;
194 cap_header = pci_conf_read32(bus, dev, func, cap_ptr);
195 cap_id = get_field_from_reg_u32(
196 cap_header, PCI_CAP_ID_MASK, PCI_CAP_ID_SHIFT);
198 if ( cap_id == PCI_CAP_ID_SECURE_DEVICE )
199 {
200 cap_type = get_field_from_reg_u32(
201 cap_header, PCI_CAP_TYPE_MASK, PCI_CAP_TYPE_SHIFT);
202 if ( cap_type == PCI_CAP_TYPE_IOMMU )
203 error = iommu_detect_callback(
204 bus, dev, func, cap_ptr);
205 }
207 cap_ptr = get_field_from_reg_u32(
208 cap_header, PCI_CAP_NEXT_PTR_MASK, PCI_CAP_NEXT_PTR_SHIFT);
209 count++;
210 }
212 return error;
213 }
215 static int __init scan_functions_for_iommu(
216 int bus, int dev, iommu_detect_callback_ptr_t iommu_detect_callback)
217 {
218 int func, hdr_type;
219 int count = 1, error = 0;
221 for ( func = 0;
222 (func < count) && !error &&
223 VALID_PCI_VENDOR_ID(pci_conf_read16(bus, dev, func,
224 PCI_VENDOR_ID));
225 func++ )
227 {
228 hdr_type = pci_conf_read8(bus, dev, func, PCI_HEADER_TYPE);
230 if ( (func == 0) && IS_PCI_MULTI_FUNCTION(hdr_type) )
231 count = PCI_MAX_FUNC_COUNT;
233 if ( IS_PCI_TYPE0_HEADER(hdr_type) ||
234 IS_PCI_TYPE1_HEADER(hdr_type) )
235 error = scan_caps_for_iommu(bus, dev, func,
236 iommu_detect_callback);
237 }
239 return error;
240 }
243 int __init scan_for_iommu(iommu_detect_callback_ptr_t iommu_detect_callback)
244 {
245 int bus, dev, error = 0;
247 for ( bus = 0; bus < PCI_MAX_BUS_COUNT && !error; ++bus )
248 for ( dev = 0; dev < PCI_MAX_DEV_COUNT && !error; ++dev )
249 error = scan_functions_for_iommu(bus, dev,
250 iommu_detect_callback);
252 return error;
253 }