blob: f6219d36227fbc25337aa0ee708307e3e9bbd615 [file] [log] [blame]
Bjorn Helgaas204d49a2009-10-26 11:20:47 -06001/*
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>
Jan Beulichb95a7bd2011-12-06 07:49:30 +000020#include <linux/module.h>
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060021#include <linux/acpi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060023
24struct ioapic {
25 acpi_handle handle;
26 u32 gsi_base;
27};
28
Bill Pemberton15856ad2012-11-21 15:35:00 -050029static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060030{
31 acpi_handle handle;
32 acpi_status status;
33 unsigned long long gsb;
34 struct ioapic *ioapic;
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060035 int ret;
36 char *type;
Bjorn Helgaase1944c62010-03-16 15:53:08 -060037 struct resource *res;
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060038
Rafael J. Wysocki3a83f992013-11-14 23:17:21 +010039 handle = ACPI_HANDLE(&dev->dev);
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060040 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
Bjorn Helgaase1944c62010-03-16 15:53:08 -060073 res = &dev->resource[0];
74 if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060075 goto exit_release;
76
77 pci_set_drvdata(dev, ioapic);
Bjorn Helgaase1944c62010-03-16 15:53:08 -060078 dev_info(&dev->dev, "%s at %pR, GSI %u\n", type, res, ioapic->gsi_base);
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060079 return 0;
80
81exit_release:
82 pci_release_region(dev, 0);
83exit_disable:
84 pci_disable_device(dev);
85exit_free:
86 kfree(ioapic);
87 return -ENODEV;
88}
89
Bill Pemberton15856ad2012-11-21 15:35:00 -050090static void ioapic_remove(struct pci_dev *dev)
Bjorn Helgaas204d49a2009-10-26 11:20:47 -060091{
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
Benoit Taine9baa3c32014-08-08 15:56:03 +0200101static const struct pci_device_id ioapic_devices[] = {
Jan Beulichb95a7bd2011-12-06 07:49:30 +0000102 { PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOAPIC, ~0) },
103 { PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOXAPIC, ~0) },
Bjorn Helgaas204d49a2009-10-26 11:20:47 -0600104 { }
105};
Jan Beulichb95a7bd2011-12-06 07:49:30 +0000106MODULE_DEVICE_TABLE(pci, ioapic_devices);
Bjorn Helgaas204d49a2009-10-26 11:20:47 -0600107
108static struct pci_driver ioapic_driver = {
109 .name = "ioapic",
110 .id_table = ioapic_devices,
111 .probe = ioapic_probe,
Bill Pemberton15856ad2012-11-21 15:35:00 -0500112 .remove = ioapic_remove,
Bjorn Helgaas204d49a2009-10-26 11:20:47 -0600113};
114
Yinghai Lu77410432014-01-02 16:05:57 -0800115static int __init ioapic_init(void)
116{
117 return pci_register_driver(&ioapic_driver);
118}
119module_init(ioapic_init);
Andrew Cookseba48cd2012-11-13 12:39:07 +0800120
121MODULE_LICENSE("GPL");