~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/pci/acpi.c

Version: ~ [ linux-5.3-rc4 ] ~ [ linux-5.2.8 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.66 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.138 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.189 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.189 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.71 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #include <linux/pci.h>
  2 #include <linux/acpi.h>
  3 #include <linux/init.h>
  4 #include <linux/irq.h>
  5 #include <linux/dmi.h>
  6 #include <linux/slab.h>
  7 #include <asm/numa.h>
  8 #include <asm/pci_x86.h>
  9 
 10 struct pci_root_info {
 11         struct acpi_device *bridge;
 12         char *name;
 13         unsigned int res_num;
 14         struct resource *res;
 15         struct list_head *resources;
 16         int busnum;
 17 };
 18 
 19 static bool pci_use_crs = true;
 20 
 21 static int __init set_use_crs(const struct dmi_system_id *id)
 22 {
 23         pci_use_crs = true;
 24         return 0;
 25 }
 26 
 27 static int __init set_nouse_crs(const struct dmi_system_id *id)
 28 {
 29         pci_use_crs = false;
 30         return 0;
 31 }
 32 
 33 static const struct dmi_system_id pci_use_crs_table[] __initconst = {
 34         /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
 35         {
 36                 .callback = set_use_crs,
 37                 .ident = "IBM System x3800",
 38                 .matches = {
 39                         DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
 40                         DMI_MATCH(DMI_PRODUCT_NAME, "x3800"),
 41                 },
 42         },
 43         /* https://bugzilla.kernel.org/show_bug.cgi?id=16007 */
 44         /* 2006 AMD HT/VIA system with two host bridges */
 45         {
 46                 .callback = set_use_crs,
 47                 .ident = "ASRock ALiveSATA2-GLAN",
 48                 .matches = {
 49                         DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
 50                 },
 51         },
 52         /* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
 53         /* 2006 AMD HT/VIA system with two host bridges */
 54         {
 55                 .callback = set_use_crs,
 56                 .ident = "ASUS M2V-MX SE",
 57                 .matches = {
 58                         DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 59                         DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
 60                         DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
 61                 },
 62         },
 63         /* https://bugzilla.kernel.org/show_bug.cgi?id=42619 */
 64         {
 65                 .callback = set_use_crs,
 66                 .ident = "MSI MS-7253",
 67                 .matches = {
 68                         DMI_MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
 69                         DMI_MATCH(DMI_BOARD_NAME, "MS-7253"),
 70                         DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
 71                 },
 72         },
 73         /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/931368 */
 74         /* https://bugs.launchpad.net/ubuntu/+source/alsa-driver/+bug/1033299 */
 75         {
 76                 .callback = set_use_crs,
 77                 .ident = "Foxconn K8M890-8237A",
 78                 .matches = {
 79                         DMI_MATCH(DMI_BOARD_VENDOR, "Foxconn"),
 80                         DMI_MATCH(DMI_BOARD_NAME, "K8M890-8237A"),
 81                         DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
 82                 },
 83         },
 84 
 85         /* Now for the blacklist.. */
 86 
 87         /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */
 88         {
 89                 .callback = set_nouse_crs,
 90                 .ident = "Dell Studio 1557",
 91                 .matches = {
 92                         DMI_MATCH(DMI_BOARD_VENDOR, "Dell Inc."),
 93                         DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1557"),
 94                         DMI_MATCH(DMI_BIOS_VERSION, "A09"),
 95                 },
 96         },
 97         /* https://bugzilla.redhat.com/show_bug.cgi?id=769657 */
 98         {
 99                 .callback = set_nouse_crs,
100                 .ident = "Thinkpad SL510",
101                 .matches = {
102                         DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
103                         DMI_MATCH(DMI_BOARD_NAME, "2847DFG"),
104                         DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"),
105                 },
106         },
107         {}
108 };
109 
110 void __init pci_acpi_crs_quirks(void)
111 {
112         int year;
113 
114         if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008)
115                 pci_use_crs = false;
116 
117         dmi_check_system(pci_use_crs_table);
118 
119         /*
120          * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that
121          * takes precedence over anything we figured out above.
122          */
123         if (pci_probe & PCI_ROOT_NO_CRS)
124                 pci_use_crs = false;
125         else if (pci_probe & PCI_USE__CRS)
126                 pci_use_crs = true;
127 
128         printk(KERN_INFO "PCI: %s host bridge windows from ACPI; "
129                "if necessary, use \"pci=%s\" and report a bug\n",
130                pci_use_crs ? "Using" : "Ignoring",
131                pci_use_crs ? "nocrs" : "use_crs");
132 }
133 
134 static acpi_status
135 resource_to_addr(struct acpi_resource *resource,
136                         struct acpi_resource_address64 *addr)
137 {
138         acpi_status status;
139         struct acpi_resource_memory24 *memory24;
140         struct acpi_resource_memory32 *memory32;
141         struct acpi_resource_fixed_memory32 *fixed_memory32;
142 
143         memset(addr, 0, sizeof(*addr));
144         switch (resource->type) {
145         case ACPI_RESOURCE_TYPE_MEMORY24:
146                 memory24 = &resource->data.memory24;
147                 addr->resource_type = ACPI_MEMORY_RANGE;
148                 addr->minimum = memory24->minimum;
149                 addr->address_length = memory24->address_length;
150                 addr->maximum = addr->minimum + addr->address_length - 1;
151                 return AE_OK;
152         case ACPI_RESOURCE_TYPE_MEMORY32:
153                 memory32 = &resource->data.memory32;
154                 addr->resource_type = ACPI_MEMORY_RANGE;
155                 addr->minimum = memory32->minimum;
156                 addr->address_length = memory32->address_length;
157                 addr->maximum = addr->minimum + addr->address_length - 1;
158                 return AE_OK;
159         case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
160                 fixed_memory32 = &resource->data.fixed_memory32;
161                 addr->resource_type = ACPI_MEMORY_RANGE;
162                 addr->minimum = fixed_memory32->address;
163                 addr->address_length = fixed_memory32->address_length;
164                 addr->maximum = addr->minimum + addr->address_length - 1;
165                 return AE_OK;
166         case ACPI_RESOURCE_TYPE_ADDRESS16:
167         case ACPI_RESOURCE_TYPE_ADDRESS32:
168         case ACPI_RESOURCE_TYPE_ADDRESS64:
169                 status = acpi_resource_to_address64(resource, addr);
170                 if (ACPI_SUCCESS(status) &&
171                     (addr->resource_type == ACPI_MEMORY_RANGE ||
172                     addr->resource_type == ACPI_IO_RANGE) &&
173                     addr->address_length > 0) {
174                         return AE_OK;
175                 }
176                 break;
177         }
178         return AE_ERROR;
179 }
180 
181 static acpi_status
182 count_resource(struct acpi_resource *acpi_res, void *data)
183 {
184         struct pci_root_info *info = data;
185         struct acpi_resource_address64 addr;
186         acpi_status status;
187 
188         status = resource_to_addr(acpi_res, &addr);
189         if (ACPI_SUCCESS(status))
190                 info->res_num++;
191         return AE_OK;
192 }
193 
194 static acpi_status
195 setup_resource(struct acpi_resource *acpi_res, void *data)
196 {
197         struct pci_root_info *info = data;
198         struct resource *res;
199         struct acpi_resource_address64 addr;
200         acpi_status status;
201         unsigned long flags;
202         u64 start, orig_end, end;
203 
204         status = resource_to_addr(acpi_res, &addr);
205         if (!ACPI_SUCCESS(status))
206                 return AE_OK;
207 
208         if (addr.resource_type == ACPI_MEMORY_RANGE) {
209                 flags = IORESOURCE_MEM;
210                 if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
211                         flags |= IORESOURCE_PREFETCH;
212         } else if (addr.resource_type == ACPI_IO_RANGE) {
213                 flags = IORESOURCE_IO;
214         } else
215                 return AE_OK;
216 
217         start = addr.minimum + addr.translation_offset;
218         orig_end = end = addr.maximum + addr.translation_offset;
219 
220         /* Exclude non-addressable range or non-addressable portion of range */
221         end = min(end, (u64)iomem_resource.end);
222         if (end <= start) {
223                 dev_info(&info->bridge->dev,
224                         "host bridge window [%#llx-%#llx] "
225                         "(ignored, not CPU addressable)\n", start, orig_end);
226                 return AE_OK;
227         } else if (orig_end != end) {
228                 dev_info(&info->bridge->dev,
229                         "host bridge window [%#llx-%#llx] "
230                         "([%#llx-%#llx] ignored, not CPU addressable)\n", 
231                         start, orig_end, end + 1, orig_end);
232         }
233 
234         res = &info->res[info->res_num];
235         res->name = info->name;
236         res->flags = flags;
237         res->start = start;
238         res->end = end;
239         res->child = NULL;
240 
241         if (!pci_use_crs) {
242                 dev_printk(KERN_DEBUG, &info->bridge->dev,
243                            "host bridge window %pR (ignored)\n", res);
244                 return AE_OK;
245         }
246 
247         info->res_num++;
248         if (addr.translation_offset)
249                 dev_info(&info->bridge->dev, "host bridge window %pR "
250                          "(PCI address [%#llx-%#llx])\n",
251                          res, res->start - addr.translation_offset,
252                          res->end - addr.translation_offset);
253         else
254                 dev_info(&info->bridge->dev, "host bridge window %pR\n", res);
255 
256         return AE_OK;
257 }
258 
259 static bool resource_contains(struct resource *res, resource_size_t point)
260 {
261         if (res->start <= point && point <= res->end)
262                 return true;
263         return false;
264 }
265 
266 static void coalesce_windows(struct pci_root_info *info, unsigned long type)
267 {
268         int i, j;
269         struct resource *res1, *res2;
270 
271         for (i = 0; i < info->res_num; i++) {
272                 res1 = &info->res[i];
273                 if (!(res1->flags & type))
274                         continue;
275 
276                 for (j = i + 1; j < info->res_num; j++) {
277                         res2 = &info->res[j];
278                         if (!(res2->flags & type))
279                                 continue;
280 
281                         /*
282                          * I don't like throwing away windows because then
283                          * our resources no longer match the ACPI _CRS, but
284                          * the kernel resource tree doesn't allow overlaps.
285                          */
286                         if (resource_contains(res1, res2->start) ||
287                             resource_contains(res1, res2->end) ||
288                             resource_contains(res2, res1->start) ||
289                             resource_contains(res2, res1->end)) {
290                                 res1->start = min(res1->start, res2->start);
291                                 res1->end = max(res1->end, res2->end);
292                                 dev_info(&info->bridge->dev,
293                                          "host bridge window expanded to %pR; %pR ignored\n",
294                                          res1, res2);
295                                 res2->flags = 0;
296                         }
297                 }
298         }
299 }
300 
301 static void add_resources(struct pci_root_info *info)
302 {
303         int i;
304         struct resource *res, *root, *conflict;
305 
306         coalesce_windows(info, IORESOURCE_MEM);
307         coalesce_windows(info, IORESOURCE_IO);
308 
309         for (i = 0; i < info->res_num; i++) {
310                 res = &info->res[i];
311 
312                 if (res->flags & IORESOURCE_MEM)
313                         root = &iomem_resource;
314                 else if (res->flags & IORESOURCE_IO)
315                         root = &ioport_resource;
316                 else
317                         continue;
318 
319                 conflict = insert_resource_conflict(root, res);
320                 if (conflict)
321                         dev_info(&info->bridge->dev,
322                                  "ignoring host bridge window %pR (conflicts with %s %pR)\n",
323                                  res, conflict->name, conflict);
324                 else
325                         pci_add_resource(info->resources, res);
326         }
327 }
328 
329 static void
330 get_current_resources(struct acpi_device *device, int busnum,
331                       int domain, struct list_head *resources)
332 {
333         struct pci_root_info info;
334         size_t size;
335 
336         info.bridge = device;
337         info.res_num = 0;
338         info.resources = resources;
339         acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
340                                 &info);
341         if (!info.res_num)
342                 return;
343 
344         size = sizeof(*info.res) * info.res_num;
345         info.res = kmalloc(size, GFP_KERNEL);
346         if (!info.res)
347                 return;
348 
349         info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum);
350         if (!info.name)
351                 goto name_alloc_fail;
352 
353         info.res_num = 0;
354         acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
355                                 &info);
356 
357         if (pci_use_crs) {
358                 add_resources(&info);
359 
360                 return;
361         }
362 
363         kfree(info.name);
364 
365 name_alloc_fail:
366         kfree(info.res);
367 }
368 
369 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
370 {
371         struct acpi_device *device = root->device;
372         int domain = root->segment;
373         int busnum = root->secondary.start;
374         LIST_HEAD(resources);
375         struct pci_bus *bus;
376         struct pci_sysdata *sd;
377         int node;
378 #ifdef CONFIG_ACPI_NUMA
379         int pxm;
380 #endif
381 
382         if (domain && !pci_domains_supported) {
383                 printk(KERN_WARNING "pci_bus %04x:%02x: "
384                        "ignored (multiple domains not supported)\n",
385                        domain, busnum);
386                 return NULL;
387         }
388 
389         node = -1;
390 #ifdef CONFIG_ACPI_NUMA
391         pxm = acpi_get_pxm(device->handle);
392         if (pxm >= 0)
393                 node = pxm_to_node(pxm);
394         if (node != -1)
395                 set_mp_bus_to_node(busnum, node);
396         else
397 #endif
398                 node = get_mp_bus_to_node(busnum);
399 
400         if (node != -1 && !node_online(node))
401                 node = -1;
402 
403         /* Allocate per-root-bus (not per bus) arch-specific data.
404          * TODO: leak; this memory is never freed.
405          * It's arguable whether it's worth the trouble to care.
406          */
407         sd = kzalloc(sizeof(*sd), GFP_KERNEL);
408         if (!sd) {
409                 printk(KERN_WARNING "pci_bus %04x:%02x: "
410                        "ignored (out of memory)\n", domain, busnum);
411                 return NULL;
412         }
413 
414         sd->domain = domain;
415         sd->node = node;
416         /*
417          * Maybe the desired pci bus has been already scanned. In such case
418          * it is unnecessary to scan the pci bus with the given domain,busnum.
419          */
420         bus = pci_find_bus(domain, busnum);
421         if (bus) {
422                 /*
423                  * If the desired bus exits, the content of bus->sysdata will
424                  * be replaced by sd.
425                  */
426                 memcpy(bus->sysdata, sd, sizeof(*sd));
427                 kfree(sd);
428         } else {
429                 get_current_resources(device, busnum, domain, &resources);
430 
431                 /*
432                  * _CRS with no apertures is normal, so only fall back to
433                  * defaults or native bridge info if we're ignoring _CRS.
434                  */
435                 if (!pci_use_crs)
436                         x86_pci_root_bus_resources(busnum, &resources);
437                 bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
438                                           &resources);
439                 if (bus)
440                         bus->subordinate = pci_scan_child_bus(bus);
441                 else
442                         pci_free_resource_list(&resources);
443         }
444 
445         /* After the PCI-E bus has been walked and all devices discovered,
446          * configure any settings of the fabric that might be necessary.
447          */
448         if (bus) {
449                 struct pci_bus *child;
450                 list_for_each_entry(child, &bus->children, node) {
451                         struct pci_dev *self = child->self;
452                         if (!self)
453                                 continue;
454 
455                         pcie_bus_configure_settings(child, self->pcie_mpss);
456                 }
457         }
458 
459         if (!bus)
460                 kfree(sd);
461 
462         if (bus && node != -1) {
463 #ifdef CONFIG_ACPI_NUMA
464                 if (pxm >= 0)
465                         dev_printk(KERN_DEBUG, &bus->dev,
466                                    "on NUMA node %d (pxm %d)\n", node, pxm);
467 #else
468                 dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
469 #endif
470         }
471 
472         return bus;
473 }
474 
475 int __init pci_acpi_init(void)
476 {
477         struct pci_dev *dev = NULL;
478 
479         if (acpi_noirq)
480                 return -ENODEV;
481 
482         printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
483         acpi_irq_penalty_init();
484         pcibios_enable_irq = acpi_pci_irq_enable;
485         pcibios_disable_irq = acpi_pci_irq_disable;
486         x86_init.pci.init_irq = x86_init_noop;
487 
488         if (pci_routeirq) {
489                 /*
490                  * PCI IRQ routing is set up by pci_enable_device(), but we
491                  * also do it here in case there are still broken drivers that
492                  * don't use pci_enable_device().
493                  */
494                 printk(KERN_INFO "PCI: Routing PCI interrupts for all devices because \"pci=routeirq\" specified\n");
495                 for_each_pci_dev(dev)
496                         acpi_pci_irq_enable(dev);
497         }
498 
499         return 0;
500 }
501 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp