Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[linux-2.6.git] / drivers / pci / ioapic.c
blob1b90579b233ae8c2d7db5efe00cc022c42fbb73a
1 /*
2 * IOAPIC/IOxAPIC/IOSAPIC driver
4 * Copyright (C) 2009 Fujitsu Limited.
5 * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
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.
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.
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>
25 struct ioapic {
26 acpi_handle handle;
27 u32 gsi_base;
30 static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
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;
40 handle = DEVICE_ACPI_HANDLE(&dev->dev);
41 if (!handle)
42 return -EINVAL;
44 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
45 if (ACPI_FAILURE(status))
46 return -EINVAL;
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.
53 ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
54 if (!ioapic)
55 return -ENOMEM;
57 ioapic->handle = handle;
58 ioapic->gsi_base = (u32) gsb;
60 if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
61 type = "IOAPIC";
62 else
63 type = "IOxAPIC";
65 ret = pci_enable_device(dev);
66 if (ret < 0)
67 goto exit_free;
69 pci_set_master(dev);
71 if (pci_request_region(dev, 0, type))
72 goto exit_disable;
74 res = &dev->resource[0];
75 if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
76 goto exit_release;
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;
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;
91 static void ioapic_remove(struct pci_dev *dev)
93 struct ioapic *ioapic = pci_get_drvdata(dev);
95 acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
96 pci_release_region(dev, 0);
97 pci_disable_device(dev);
98 kfree(ioapic);
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) },
107 MODULE_DEVICE_TABLE(pci, ioapic_devices);
109 static struct pci_driver ioapic_driver = {
110 .name = "ioapic",
111 .id_table = ioapic_devices,
112 .probe = ioapic_probe,
113 .remove = ioapic_remove,
116 module_pci_driver(ioapic_driver);
118 MODULE_LICENSE("GPL");