aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/hotplug
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2008-12-16 22:08:15 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-01-07 14:13:10 -0500
commite046cbd6c05ee859244245d7beeac395cd0057b3 (patch)
tree1d1c3f434a77b522af098c54114d4fee7bd96a6e /drivers/pci/hotplug
parentc9ffa5a586a97da4d552f89b8f39eea79a63a612 (diff)
PCI: pciehp: add auto option to pciehp_detect_mode
ACPI based hot-pluggable PCIe slot detection logic was added to prevent the problem non hot-pluggable PCIe slot was detected as hot-pluggable. The slot detection logic can be selected through 'pciehp_detect_mode', but it would be better if it is selected automatically. This patch adds 'auto' option for 'pciehp_detect_mode'. When it is specified, pciehp judges which 'acpi' or 'pcie' should be used. It seems that the physical slot number is duplicated among some slots on most of the platforms with the above-mentioned problem. So 'auto' mode uses this information to judge which 'acpi' or 'pcie' should be used. That is, if duplicated physical slot numbers are detected, 'acpi' mode is used. This method is not perfect, but it's realistic. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci/hotplug')
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
index 0cd49b728045..88a5c57f2e5b 100644
--- a/drivers/pci/hotplug/pciehp_acpi.c
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -28,15 +28,18 @@
28 28
29#define PCIEHP_DETECT_PCIE (0) 29#define PCIEHP_DETECT_PCIE (0)
30#define PCIEHP_DETECT_ACPI (1) 30#define PCIEHP_DETECT_ACPI (1)
31#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_PCIE 31#define PCIEHP_DETECT_AUTO (2)
32#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO
32 33
33static int slot_detection_mode; 34static int slot_detection_mode;
34static char *pciehp_detect_mode; 35static char *pciehp_detect_mode;
35module_param(pciehp_detect_mode, charp, 0444); 36module_param(pciehp_detect_mode, charp, 0444);
36MODULE_PARM_DESC(pciehp_detect_mode, 37MODULE_PARM_DESC(pciehp_detect_mode,
37 "Slot detection mode: pcie, acpi\n" 38 "Slot detection mode: pcie, acpi, auto\n"
38 " pcie - Use PCIe based slot detection (default)\n" 39 " pcie - Use PCIe based slot detection\n"
39 " acpi - Use ACPI for slot detection\n"); 40 " acpi - Use ACPI for slot detection\n"
41 " auto(default) - Auto select mode. Use acpi option if duplicate\n"
42 " slot ids are found. Otherwise, use pcie option\n");
40 43
41static int is_ejectable(acpi_handle handle) 44static int is_ejectable(acpi_handle handle)
42{ 45{
@@ -103,12 +106,81 @@ static int __init parse_detect_mode(void)
103 return PCIEHP_DETECT_PCIE; 106 return PCIEHP_DETECT_PCIE;
104 if (!strcmp(pciehp_detect_mode, "acpi")) 107 if (!strcmp(pciehp_detect_mode, "acpi"))
105 return PCIEHP_DETECT_ACPI; 108 return PCIEHP_DETECT_ACPI;
109 if (!strcmp(pciehp_detect_mode, "auto"))
110 return PCIEHP_DETECT_AUTO;
106 warn("bad specifier '%s' for pciehp_detect_mode. Use default\n", 111 warn("bad specifier '%s' for pciehp_detect_mode. Use default\n",
107 pciehp_detect_mode); 112 pciehp_detect_mode);
108 return PCIEHP_DETECT_DEFAULT; 113 return PCIEHP_DETECT_DEFAULT;
109} 114}
110 115
116static struct pcie_port_service_id __initdata port_pci_ids[] = {
117 {
118 .vendor = PCI_ANY_ID,
119 .device = PCI_ANY_ID,
120 .port_type = PCIE_ANY_PORT,
121 .service_type = PCIE_PORT_SERVICE_HP,
122 .driver_data = 0,
123 }, { /* end: all zeroes */ }
124};
125
126static int __initdata dup_slot_id;
127static int __initdata acpi_slot_detected;
128static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots);
129
130/* Dummy driver for dumplicate name detection */
131static int __init dummy_probe(struct pcie_device *dev,
132 const struct pcie_port_service_id *id)
133{
134 int pos;
135 u32 slot_cap;
136 struct slot *slot, *tmp;
137 struct pci_dev *pdev = dev->port;
138 if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
139 return -ENOMEM;
140 /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
141 if (pciehp_get_hp_hw_control_from_firmware(pdev))
142 return -ENODEV;
143 if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP)))
144 return -ENODEV;
145 pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
146 slot->number = slot_cap >> 19;
147 list_for_each_entry(tmp, &dummy_slots, slot_list) {
148 if (tmp->number == slot->number)
149 dup_slot_id++;
150 }
151 list_add_tail(&slot->slot_list, &dummy_slots);
152 if (!acpi_slot_detected && pciehp_detect_acpi_slot(pdev->subordinate))
153 acpi_slot_detected = 1;
154 return -ENODEV; /* dummy driver always returns error */
155}
156
157static struct pcie_port_service_driver __initdata dummy_driver = {
158 .name = "pciehp_dummy",
159 .id_table = port_pci_ids,
160 .probe = dummy_probe,
161};
162
163static int __init select_detection_mode(void)
164{
165 struct slot *slot, *tmp;
166 pcie_port_service_register(&dummy_driver);
167 pcie_port_service_unregister(&dummy_driver);
168 list_for_each_entry_safe(slot, tmp, &dummy_slots, slot_list) {
169 list_del(&slot->slot_list);
170 kfree(slot);
171 }
172 if (acpi_slot_detected && dup_slot_id)
173 return PCIEHP_DETECT_ACPI;
174 return PCIEHP_DETECT_PCIE;
175}
176
111void __init pciehp_acpi_slot_detection_init(void) 177void __init pciehp_acpi_slot_detection_init(void)
112{ 178{
113 slot_detection_mode = parse_detect_mode(); 179 slot_detection_mode = parse_detect_mode();
180 if (slot_detection_mode != PCIEHP_DETECT_AUTO)
181 goto out;
182 slot_detection_mode = select_detection_mode();
183out:
184 if (slot_detection_mode == PCIEHP_DETECT_ACPI)
185 info("Using ACPI for slot detection.\n");
114} 186}