Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[linux-drm-fsl-dcu.git] / drivers / pci / ioapic.c
1 /*
2  * IOAPIC/IOxAPIC/IOSAPIC driver
3  *
4  * Copyright (C) 2009 Fujitsu Limited.
5  * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 /*
13  * This driver manages PCI I/O APICs added by hotplug after boot.  We try to
14  * claim all I/O APIC PCI devices, but those present at boot were registered
15  * when we parsed the ACPI MADT, so we'll fail when we try to re-register
16  * them.
17  */
18
19 #include <linux/pci.h>
20 #include <linux/module.h>
21 #include <linux/acpi.h>
22 #include <linux/slab.h>
23 #include <acpi/acpi_bus.h>
24
25 struct ioapic {
26         acpi_handle     handle;
27         u32             gsi_base;
28 };
29
30 static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
31 {
32         acpi_handle handle;
33         acpi_status status;
34         unsigned long long gsb;
35         struct ioapic *ioapic;
36         int ret;
37         char *type;
38         struct resource *res;
39
40         handle = ACPI_HANDLE(&dev->dev);
41         if (!handle)
42                 return -EINVAL;
43
44         status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
45         if (ACPI_FAILURE(status))
46                 return -EINVAL;
47
48         /*
49          * The previous code in acpiphp evaluated _MAT if _GSB failed, but
50          * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
51          */
52
53         ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
54         if (!ioapic)
55                 return -ENOMEM;
56
57         ioapic->handle = handle;
58         ioapic->gsi_base = (u32) gsb;
59
60         if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
61                 type = "IOAPIC";
62         else
63                 type = "IOxAPIC";
64
65         ret = pci_enable_device(dev);
66         if (ret < 0)
67                 goto exit_free;
68
69         pci_set_master(dev);
70
71         if (pci_request_region(dev, 0, type))
72                 goto exit_disable;
73
74         res = &dev->resource[0];
75         if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
76                 goto exit_release;
77
78         pci_set_drvdata(dev, ioapic);
79         dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base);
80         return 0;
81
82 exit_release:
83         pci_release_region(dev, 0);
84 exit_disable:
85         pci_disable_device(dev);
86 exit_free:
87         kfree(ioapic);
88         return -ENODEV;
89 }
90
91 static void ioapic_remove(struct pci_dev *dev)
92 {
93         struct ioapic *ioapic = pci_get_drvdata(dev);
94
95         acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
96         pci_release_region(dev, 0);
97         pci_disable_device(dev);
98         kfree(ioapic);
99 }
100
101
102 static DEFINE_PCI_DEVICE_TABLE(ioapic_devices) = {
103         { PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOAPIC, ~0) },
104         { PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOXAPIC, ~0) },
105         { }
106 };
107 MODULE_DEVICE_TABLE(pci, ioapic_devices);
108
109 static struct pci_driver ioapic_driver = {
110         .name           = "ioapic",
111         .id_table       = ioapic_devices,
112         .probe          = ioapic_probe,
113         .remove         = ioapic_remove,
114 };
115
116 module_pci_driver(ioapic_driver);
117
118 MODULE_LICENSE("GPL");