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 24struct ioapic { 25 acpi_handle handle; 26 u32 gsi_base; 27}; 28 29static 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 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 90static 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 101static 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 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