]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/pci/ioapic.c
Merge branch 'core-hweight-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.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/acpi.h>
21 #include <linux/slab.h>
22 #include <acpi/acpi_bus.h>
23
24 struct ioapic {
25         acpi_handle     handle;
26         u32             gsi_base;
27 };
28
29 static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
30 {
31         acpi_handle handle;
32         acpi_status status;
33         unsigned long long gsb;
34         struct ioapic *ioapic;
35         int ret;
36         char *type;
37         struct resource *res;
38
39         handle = DEVICE_ACPI_HANDLE(&dev->dev);
40         if (!handle)
41                 return -EINVAL;
42
43         status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
44         if (ACPI_FAILURE(status))
45                 return -EINVAL;
46
47         /*
48          * The previous code in acpiphp evaluated _MAT if _GSB failed, but
49          * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
50          */
51
52         ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
53         if (!ioapic)
54                 return -ENOMEM;
55
56         ioapic->handle = handle;
57         ioapic->gsi_base = (u32) gsb;
58
59         if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
60                 type = "IOAPIC";
61         else
62                 type = "IOxAPIC";
63
64         ret = pci_enable_device(dev);
65         if (ret < 0)
66                 goto exit_free;
67
68         pci_set_master(dev);
69
70         if (pci_request_region(dev, 0, type))
71                 goto exit_disable;
72
73         res = &dev->resource[0];
74         if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
75                 goto exit_release;
76
77         pci_set_drvdata(dev, ioapic);
78         dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base);
79         return 0;
80
81 exit_release:
82         pci_release_region(dev, 0);
83 exit_disable:
84         pci_disable_device(dev);
85 exit_free:
86         kfree(ioapic);
87         return -ENODEV;
88 }
89
90 static void ioapic_remove(struct pci_dev *dev)
91 {
92         struct ioapic *ioapic = pci_get_drvdata(dev);
93
94         acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
95         pci_release_region(dev, 0);
96         pci_disable_device(dev);
97         kfree(ioapic);
98 }
99
100
101 static struct pci_device_id ioapic_devices[] = {
102         { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
103           PCI_CLASS_SYSTEM_PIC_IOAPIC << 8, 0xffff00, },
104         { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
105           PCI_CLASS_SYSTEM_PIC_IOXAPIC << 8, 0xffff00, },
106         { }
107 };
108
109 static struct pci_driver ioapic_driver = {
110         .name           = "ioapic",
111         .id_table       = ioapic_devices,
112         .probe          = ioapic_probe,
113         .remove         = __devexit_p(ioapic_remove),
114 };
115
116 static int __init ioapic_init(void)
117 {
118         return pci_register_driver(&ioapic_driver);
119 }
120
121 static void __exit ioapic_exit(void)
122 {
123         pci_unregister_driver(&ioapic_driver);
124 }
125
126 module_init(ioapic_init);
127 module_exit(ioapic_exit);