Root/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
25struct ioapic {
26    acpi_handle handle;
27    u32 gsi_base;
28};
29
30static int __devinit 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 = DEVICE_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
82exit_release:
83    pci_release_region(dev, 0);
84exit_disable:
85    pci_disable_device(dev);
86exit_free:
87    kfree(ioapic);
88    return -ENODEV;
89}
90
91static void __devexit 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
102static 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};
107MODULE_DEVICE_TABLE(pci, ioapic_devices);
108
109static 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
116static int __init ioapic_init(void)
117{
118    return pci_register_driver(&ioapic_driver);
119}
120
121static void __exit ioapic_exit(void)
122{
123    pci_unregister_driver(&ioapic_driver);
124}
125
126module_init(ioapic_init);
127module_exit(ioapic_exit);
128

Archive Download this file



interactive