Blame view

kernel/linux-imx6_3.14.28/drivers/pci/ioapic.c 2.69 KB
6b13f685e   김민수   BSP 최초 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  /*
   * IOAPIC/IOxAPIC/IOSAPIC driver
   *
   * Copyright (C) 2009 Fujitsu Limited.
   * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  /*
   * This driver manages PCI I/O APICs added by hotplug after boot.  We try to
   * claim all I/O APIC PCI devices, but those present at boot were registered
   * when we parsed the ACPI MADT, so we'll fail when we try to re-register
   * them.
   */
  
  #include <linux/pci.h>
  #include <linux/module.h>
  #include <linux/acpi.h>
  #include <linux/slab.h>
  
  struct ioapic {
  	acpi_handle	handle;
  	u32		gsi_base;
  };
  
  static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
  {
  	acpi_handle handle;
  	acpi_status status;
  	unsigned long long gsb;
  	struct ioapic *ioapic;
  	int ret;
  	char *type;
  	struct resource *res;
  
  	handle = ACPI_HANDLE(&dev->dev);
  	if (!handle)
  		return -EINVAL;
  
  	status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
  	if (ACPI_FAILURE(status))
  		return -EINVAL;
  
  	/*
  	 * The previous code in acpiphp evaluated _MAT if _GSB failed, but
  	 * ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
  	 */
  
  	ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
  	if (!ioapic)
  		return -ENOMEM;
  
  	ioapic->handle = handle;
  	ioapic->gsi_base = (u32) gsb;
  
  	if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
  		type = "IOAPIC";
  	else
  		type = "IOxAPIC";
  
  	ret = pci_enable_device(dev);
  	if (ret < 0)
  		goto exit_free;
  
  	pci_set_master(dev);
  
  	if (pci_request_region(dev, 0, type))
  		goto exit_disable;
  
  	res = &dev->resource[0];
  	if (acpi_register_ioapic(ioapic->handle, res->start, ioapic->gsi_base))
  		goto exit_release;
  
  	pci_set_drvdata(dev, ioapic);
  	dev_info(&dev->dev, "%s at %pR, GSI %u
  ", type, res, ioapic->gsi_base);
  	return 0;
  
  exit_release:
  	pci_release_region(dev, 0);
  exit_disable:
  	pci_disable_device(dev);
  exit_free:
  	kfree(ioapic);
  	return -ENODEV;
  }
  
  static void ioapic_remove(struct pci_dev *dev)
  {
  	struct ioapic *ioapic = pci_get_drvdata(dev);
  
  	acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
  	pci_release_region(dev, 0);
  	pci_disable_device(dev);
  	kfree(ioapic);
  }
  
  
  static DEFINE_PCI_DEVICE_TABLE(ioapic_devices) = {
  	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOAPIC, ~0) },
  	{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_PIC_IOXAPIC, ~0) },
  	{ }
  };
  MODULE_DEVICE_TABLE(pci, ioapic_devices);
  
  static struct pci_driver ioapic_driver = {
  	.name		= "ioapic",
  	.id_table	= ioapic_devices,
  	.probe		= ioapic_probe,
  	.remove		= ioapic_remove,
  };
  
  static int __init ioapic_init(void)
  {
  	return pci_register_driver(&ioapic_driver);
  }
  module_init(ioapic_init);
  
  MODULE_LICENSE("GPL");