linux/drivers/pci/ioapic.c
<<
>>
Prefs
   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 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 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         = 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
 129MODULE_LICENSE("GPL");
 130
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.