Merge branch 'virtex-for-2.6.25' of git://git.secretlab.ca/git/linux-2.6-virtex into...
[linux-2.6] / drivers / pci / dmar.c
1 /*
2  * Copyright (c) 2006, Intel Corporation.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15  * Place - Suite 330, Boston, MA 02111-1307 USA.
16  *
17  *      Copyright (C) Ashok Raj <ashok.raj@intel.com>
18  *      Copyright (C) Shaohua Li <shaohua.li@intel.com>
19  *      Copyright (C) Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
20  *
21  *      This file implements early detection/parsing of DMA Remapping Devices
22  * reported to OS through BIOS via DMA remapping reporting (DMAR) ACPI
23  * tables.
24  */
25
26 #include <linux/pci.h>
27 #include <linux/dmar.h>
28 #include "iova.h"
29
30 #undef PREFIX
31 #define PREFIX "DMAR:"
32
33 /* No locks are needed as DMA remapping hardware unit
34  * list is constructed at boot time and hotplug of
35  * these units are not supported by the architecture.
36  */
37 LIST_HEAD(dmar_drhd_units);
38 LIST_HEAD(dmar_rmrr_units);
39
40 static struct acpi_table_header * __initdata dmar_tbl;
41
42 static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
43 {
44         /*
45          * add INCLUDE_ALL at the tail, so scan the list will find it at
46          * the very end.
47          */
48         if (drhd->include_all)
49                 list_add_tail(&drhd->list, &dmar_drhd_units);
50         else
51                 list_add(&drhd->list, &dmar_drhd_units);
52 }
53
54 static void __init dmar_register_rmrr_unit(struct dmar_rmrr_unit *rmrr)
55 {
56         list_add(&rmrr->list, &dmar_rmrr_units);
57 }
58
59 static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
60                                            struct pci_dev **dev, u16 segment)
61 {
62         struct pci_bus *bus;
63         struct pci_dev *pdev = NULL;
64         struct acpi_dmar_pci_path *path;
65         int count;
66
67         bus = pci_find_bus(segment, scope->bus);
68         path = (struct acpi_dmar_pci_path *)(scope + 1);
69         count = (scope->length - sizeof(struct acpi_dmar_device_scope))
70                 / sizeof(struct acpi_dmar_pci_path);
71
72         while (count) {
73                 if (pdev)
74                         pci_dev_put(pdev);
75                 /*
76                  * Some BIOSes list non-exist devices in DMAR table, just
77                  * ignore it
78                  */
79                 if (!bus) {
80                         printk(KERN_WARNING
81                         PREFIX "Device scope bus [%d] not found\n",
82                         scope->bus);
83                         break;
84                 }
85                 pdev = pci_get_slot(bus, PCI_DEVFN(path->dev, path->fn));
86                 if (!pdev) {
87                         printk(KERN_WARNING PREFIX
88                         "Device scope device [%04x:%02x:%02x.%02x] not found\n",
89                                 segment, bus->number, path->dev, path->fn);
90                         break;
91                 }
92                 path ++;
93                 count --;
94                 bus = pdev->subordinate;
95         }
96         if (!pdev) {
97                 printk(KERN_WARNING PREFIX
98                 "Device scope device [%04x:%02x:%02x.%02x] not found\n",
99                 segment, scope->bus, path->dev, path->fn);
100                 *dev = NULL;
101                 return 0;
102         }
103         if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
104                         pdev->subordinate) || (scope->entry_type == \
105                         ACPI_DMAR_SCOPE_TYPE_BRIDGE && !pdev->subordinate)) {
106                 pci_dev_put(pdev);
107                 printk(KERN_WARNING PREFIX
108                         "Device scope type does not match for %s\n",
109                          pci_name(pdev));
110                 return -EINVAL;
111         }
112         *dev = pdev;
113         return 0;
114 }
115
116 static int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
117                                        struct pci_dev ***devices, u16 segment)
118 {
119         struct acpi_dmar_device_scope *scope;
120         void * tmp = start;
121         int index;
122         int ret;
123
124         *cnt = 0;
125         while (start < end) {
126                 scope = start;
127                 if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
128                     scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
129                         (*cnt)++;
130                 else
131                         printk(KERN_WARNING PREFIX
132                                 "Unsupported device scope\n");
133                 start += scope->length;
134         }
135         if (*cnt == 0)
136                 return 0;
137
138         *devices = kcalloc(*cnt, sizeof(struct pci_dev *), GFP_KERNEL);
139         if (!*devices)
140                 return -ENOMEM;
141
142         start = tmp;
143         index = 0;
144         while (start < end) {
145                 scope = start;
146                 if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
147                     scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE) {
148                         ret = dmar_parse_one_dev_scope(scope,
149                                 &(*devices)[index], segment);
150                         if (ret) {
151                                 kfree(*devices);
152                                 return ret;
153                         }
154                         index ++;
155                 }
156                 start += scope->length;
157         }
158
159         return 0;
160 }
161
162 /**
163  * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
164  * structure which uniquely represent one DMA remapping hardware unit
165  * present in the platform
166  */
167 static int __init
168 dmar_parse_one_drhd(struct acpi_dmar_header *header)
169 {
170         struct acpi_dmar_hardware_unit *drhd;
171         struct dmar_drhd_unit *dmaru;
172         int ret = 0;
173         static int include_all;
174
175         dmaru = kzalloc(sizeof(*dmaru), GFP_KERNEL);
176         if (!dmaru)
177                 return -ENOMEM;
178
179         drhd = (struct acpi_dmar_hardware_unit *)header;
180         dmaru->reg_base_addr = drhd->address;
181         dmaru->include_all = drhd->flags & 0x1; /* BIT0: INCLUDE_ALL */
182
183         if (!dmaru->include_all)
184                 ret = dmar_parse_dev_scope((void *)(drhd + 1),
185                                 ((void *)drhd) + header->length,
186                                 &dmaru->devices_cnt, &dmaru->devices,
187                                 drhd->segment);
188         else {
189                 /* Only allow one INCLUDE_ALL */
190                 if (include_all) {
191                         printk(KERN_WARNING PREFIX "Only one INCLUDE_ALL "
192                                 "device scope is allowed\n");
193                         ret = -EINVAL;
194                 }
195                 include_all = 1;
196         }
197
198         if (ret || (dmaru->devices_cnt == 0 && !dmaru->include_all))
199                 kfree(dmaru);
200         else
201                 dmar_register_drhd_unit(dmaru);
202         return ret;
203 }
204
205 static int __init
206 dmar_parse_one_rmrr(struct acpi_dmar_header *header)
207 {
208         struct acpi_dmar_reserved_memory *rmrr;
209         struct dmar_rmrr_unit *rmrru;
210         int ret = 0;
211
212         rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
213         if (!rmrru)
214                 return -ENOMEM;
215
216         rmrr = (struct acpi_dmar_reserved_memory *)header;
217         rmrru->base_address = rmrr->base_address;
218         rmrru->end_address = rmrr->end_address;
219         ret = dmar_parse_dev_scope((void *)(rmrr + 1),
220                 ((void *)rmrr) + header->length,
221                 &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
222
223         if (ret || (rmrru->devices_cnt == 0))
224                 kfree(rmrru);
225         else
226                 dmar_register_rmrr_unit(rmrru);
227         return ret;
228 }
229
230 static void __init
231 dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
232 {
233         struct acpi_dmar_hardware_unit *drhd;
234         struct acpi_dmar_reserved_memory *rmrr;
235
236         switch (header->type) {
237         case ACPI_DMAR_TYPE_HARDWARE_UNIT:
238                 drhd = (struct acpi_dmar_hardware_unit *)header;
239                 printk (KERN_INFO PREFIX
240                         "DRHD (flags: 0x%08x)base: 0x%016Lx\n",
241                         drhd->flags, drhd->address);
242                 break;
243         case ACPI_DMAR_TYPE_RESERVED_MEMORY:
244                 rmrr = (struct acpi_dmar_reserved_memory *)header;
245
246                 printk (KERN_INFO PREFIX
247                         "RMRR base: 0x%016Lx end: 0x%016Lx\n",
248                         rmrr->base_address, rmrr->end_address);
249                 break;
250         }
251 }
252
253 /**
254  * parse_dmar_table - parses the DMA reporting table
255  */
256 static int __init
257 parse_dmar_table(void)
258 {
259         struct acpi_table_dmar *dmar;
260         struct acpi_dmar_header *entry_header;
261         int ret = 0;
262
263         dmar = (struct acpi_table_dmar *)dmar_tbl;
264         if (!dmar)
265                 return -ENODEV;
266
267         if (dmar->width < PAGE_SHIFT_4K - 1) {
268                 printk(KERN_WARNING PREFIX "Invalid DMAR haw\n");
269                 return -EINVAL;
270         }
271
272         printk (KERN_INFO PREFIX "Host address width %d\n",
273                 dmar->width + 1);
274
275         entry_header = (struct acpi_dmar_header *)(dmar + 1);
276         while (((unsigned long)entry_header) <
277                         (((unsigned long)dmar) + dmar_tbl->length)) {
278                 dmar_table_print_dmar_entry(entry_header);
279
280                 switch (entry_header->type) {
281                 case ACPI_DMAR_TYPE_HARDWARE_UNIT:
282                         ret = dmar_parse_one_drhd(entry_header);
283                         break;
284                 case ACPI_DMAR_TYPE_RESERVED_MEMORY:
285                         ret = dmar_parse_one_rmrr(entry_header);
286                         break;
287                 default:
288                         printk(KERN_WARNING PREFIX
289                                 "Unknown DMAR structure type\n");
290                         ret = 0; /* for forward compatibility */
291                         break;
292                 }
293                 if (ret)
294                         break;
295
296                 entry_header = ((void *)entry_header + entry_header->length);
297         }
298         return ret;
299 }
300
301
302 int __init dmar_table_init(void)
303 {
304
305         int ret;
306
307         ret = parse_dmar_table();
308         if (ret) {
309                 printk(KERN_INFO PREFIX "parse DMAR table failure.\n");
310                 return ret;
311         }
312
313         if (list_empty(&dmar_drhd_units)) {
314                 printk(KERN_INFO PREFIX "No DMAR devices found\n");
315                 return -ENODEV;
316         }
317
318         if (list_empty(&dmar_rmrr_units)) {
319                 printk(KERN_INFO PREFIX "No RMRR found\n");
320                 return -ENODEV;
321         }
322
323         return 0;
324 }
325
326 /**
327  * early_dmar_detect - checks to see if the platform supports DMAR devices
328  */
329 int __init early_dmar_detect(void)
330 {
331         acpi_status status = AE_OK;
332
333         /* if we could find DMAR table, then there are DMAR devices */
334         status = acpi_get_table(ACPI_SIG_DMAR, 0,
335                                 (struct acpi_table_header **)&dmar_tbl);
336
337         if (ACPI_SUCCESS(status) && !dmar_tbl) {
338                 printk (KERN_WARNING PREFIX "Unable to map DMAR\n");
339                 status = AE_NOT_FOUND;
340         }
341
342         return (ACPI_SUCCESS(status) ? 1 : 0);
343 }