aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/pci_slot.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/pci_slot.c')
-rw-r--r--drivers/acpi/pci_slot.c170
1 files changed, 24 insertions, 146 deletions
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index cd1434eb1de8..033d1179bdb5 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -9,6 +9,9 @@
9 * Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P. 9 * Copyright (C) 2007-2008 Hewlett-Packard Development Company, L.P.
10 * Alex Chiang <achiang@hp.com> 10 * Alex Chiang <achiang@hp.com>
11 * 11 *
12 * Copyright (C) 2013 Huawei Tech. Co., Ltd.
13 * Jiang Liu <jiang.liu@huawei.com>
14 *
12 * This program is free software; you can redistribute it and/or modify it 15 * This program is free software; you can redistribute it and/or modify it
13 * under the terms and conditions of the GNU General Public License, 16 * under the terms and conditions of the GNU General Public License,
14 * version 2, as published by the Free Software Foundation. 17 * version 2, as published by the Free Software Foundation.
@@ -28,10 +31,9 @@
28#include <linux/init.h> 31#include <linux/init.h>
29#include <linux/slab.h> 32#include <linux/slab.h>
30#include <linux/types.h> 33#include <linux/types.h>
34#include <linux/list.h>
31#include <linux/pci.h> 35#include <linux/pci.h>
32#include <linux/acpi.h> 36#include <linux/acpi.h>
33#include <acpi/acpi_bus.h>
34#include <acpi/acpi_drivers.h>
35#include <linux/dmi.h> 37#include <linux/dmi.h>
36 38
37static bool debug; 39static bool debug;
@@ -61,20 +63,12 @@ ACPI_MODULE_NAME("pci_slot");
61#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */ 63#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
62 64
63struct acpi_pci_slot { 65struct acpi_pci_slot {
64 acpi_handle root_handle; /* handle of the root bridge */
65 struct pci_slot *pci_slot; /* corresponding pci_slot */ 66 struct pci_slot *pci_slot; /* corresponding pci_slot */
66 struct list_head list; /* node in the list of slots */ 67 struct list_head list; /* node in the list of slots */
67}; 68};
68 69
69static int acpi_pci_slot_add(struct acpi_pci_root *root);
70static void acpi_pci_slot_remove(struct acpi_pci_root *root);
71
72static LIST_HEAD(slot_list); 70static LIST_HEAD(slot_list);
73static DEFINE_MUTEX(slot_list_lock); 71static DEFINE_MUTEX(slot_list_lock);
74static struct acpi_pci_driver acpi_pci_slot_driver = {
75 .add = acpi_pci_slot_add,
76 .remove = acpi_pci_slot_remove,
77};
78 72
79static int 73static int
80check_slot(acpi_handle handle, unsigned long long *sun) 74check_slot(acpi_handle handle, unsigned long long *sun)
@@ -113,21 +107,8 @@ out:
113 return device; 107 return device;
114} 108}
115 109
116struct callback_args {
117 acpi_walk_callback user_function; /* only for walk_p2p_bridge */
118 struct pci_bus *pci_bus;
119 acpi_handle root_handle;
120};
121
122/* 110/*
123 * register_slot 111 * Check whether handle has an associated slot and create PCI slot if it has.
124 *
125 * Called once for each SxFy object in the namespace. Don't worry about
126 * calling pci_create_slot multiple times for the same pci_bus:device,
127 * since each subsequent call simply bumps the refcount on the pci_slot.
128 *
129 * The number of calls to pci_destroy_slot from unregister_slot is
130 * symmetrical.
131 */ 112 */
132static acpi_status 113static acpi_status
133register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) 114register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -137,13 +118,22 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
137 char name[SLOT_NAME_SIZE]; 118 char name[SLOT_NAME_SIZE];
138 struct acpi_pci_slot *slot; 119 struct acpi_pci_slot *slot;
139 struct pci_slot *pci_slot; 120 struct pci_slot *pci_slot;
140 struct callback_args *parent_context = context; 121 struct pci_bus *pci_bus = context;
141 struct pci_bus *pci_bus = parent_context->pci_bus;
142 122
143 device = check_slot(handle, &sun); 123 device = check_slot(handle, &sun);
144 if (device < 0) 124 if (device < 0)
145 return AE_OK; 125 return AE_OK;
146 126
127 /*
128 * There may be multiple PCI functions associated with the same slot.
129 * Check whether PCI slot has already been created for this PCI device.
130 */
131 list_for_each_entry(slot, &slot_list, list) {
132 pci_slot = slot->pci_slot;
133 if (pci_slot->bus == pci_bus && pci_slot->number == device)
134 return AE_OK;
135 }
136
147 slot = kmalloc(sizeof(*slot), GFP_KERNEL); 137 slot = kmalloc(sizeof(*slot), GFP_KERNEL);
148 if (!slot) { 138 if (!slot) {
149 err("%s: cannot allocate memory\n", __func__); 139 err("%s: cannot allocate memory\n", __func__);
@@ -158,12 +148,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
158 return AE_OK; 148 return AE_OK;
159 } 149 }
160 150
161 slot->root_handle = parent_context->root_handle;
162 slot->pci_slot = pci_slot; 151 slot->pci_slot = pci_slot;
163 INIT_LIST_HEAD(&slot->list);
164 mutex_lock(&slot_list_lock);
165 list_add(&slot->list, &slot_list); 152 list_add(&slot->list, &slot_list);
166 mutex_unlock(&slot_list_lock);
167 153
168 get_device(&pci_bus->dev); 154 get_device(&pci_bus->dev);
169 155
@@ -173,131 +159,24 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
173 return AE_OK; 159 return AE_OK;
174} 160}
175 161
176/* 162void acpi_pci_slot_enumerate(struct pci_bus *bus, acpi_handle handle)
177 * walk_p2p_bridge - discover and walk p2p bridges
178 * @handle: points to an acpi_pci_root
179 * @context: p2p_bridge_context pointer
180 *
181 * Note that when we call ourselves recursively, we pass a different
182 * value of pci_bus in the child_context.
183 */
184static acpi_status
185walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
186{
187 int device, function;
188 unsigned long long adr;
189 acpi_status status;
190 acpi_handle dummy_handle;
191 acpi_walk_callback user_function;
192
193 struct pci_dev *dev;
194 struct pci_bus *pci_bus;
195 struct callback_args child_context;
196 struct callback_args *parent_context = context;
197
198 pci_bus = parent_context->pci_bus;
199 user_function = parent_context->user_function;
200
201 status = acpi_get_handle(handle, "_ADR", &dummy_handle);
202 if (ACPI_FAILURE(status))
203 return AE_OK;
204
205 status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
206 if (ACPI_FAILURE(status))
207 return AE_OK;
208
209 device = (adr >> 16) & 0xffff;
210 function = adr & 0xffff;
211
212 dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
213 if (!dev || !dev->subordinate)
214 goto out;
215
216 child_context.pci_bus = dev->subordinate;
217 child_context.user_function = user_function;
218 child_context.root_handle = parent_context->root_handle;
219
220 dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
221 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
222 user_function, NULL, &child_context, NULL);
223 if (ACPI_FAILURE(status))
224 goto out;
225
226 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
227 walk_p2p_bridge, NULL, &child_context, NULL);
228out:
229 pci_dev_put(dev);
230 return AE_OK;
231}
232
233/*
234 * walk_root_bridge - generic root bridge walker
235 * @root: poiner of an acpi_pci_root
236 * @user_function: user callback for slot objects
237 *
238 * Call user_function for all objects underneath this root bridge.
239 * Walk p2p bridges underneath us and call user_function on those too.
240 */
241static int
242walk_root_bridge(struct acpi_pci_root *root, acpi_walk_callback user_function)
243{
244 acpi_status status;
245 acpi_handle handle = root->device->handle;
246 struct pci_bus *pci_bus = root->bus;
247 struct callback_args context;
248
249 context.pci_bus = pci_bus;
250 context.user_function = user_function;
251 context.root_handle = handle;
252
253 dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
254 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
255 user_function, NULL, &context, NULL);
256 if (ACPI_FAILURE(status))
257 return status;
258
259 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
260 walk_p2p_bridge, NULL, &context, NULL);
261 if (ACPI_FAILURE(status))
262 err("%s: walk_p2p_bridge failure - %d\n", __func__, status);
263
264 return status;
265}
266
267/*
268 * acpi_pci_slot_add
269 * @handle: points to an acpi_pci_root
270 */
271static int
272acpi_pci_slot_add(struct acpi_pci_root *root)
273{ 163{
274 acpi_status status; 164 mutex_lock(&slot_list_lock);
275 165 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
276 status = walk_root_bridge(root, register_slot); 166 register_slot, NULL, bus, NULL);
277 if (ACPI_FAILURE(status)) 167 mutex_unlock(&slot_list_lock);
278 err("%s: register_slot failure - %d\n", __func__, status);
279
280 return status;
281} 168}
282 169
283/* 170void acpi_pci_slot_remove(struct pci_bus *bus)
284 * acpi_pci_slot_remove
285 * @handle: points to an acpi_pci_root
286 */
287static void
288acpi_pci_slot_remove(struct acpi_pci_root *root)
289{ 171{
290 struct acpi_pci_slot *slot, *tmp; 172 struct acpi_pci_slot *slot, *tmp;
291 struct pci_bus *pbus;
292 acpi_handle handle = root->device->handle;
293 173
294 mutex_lock(&slot_list_lock); 174 mutex_lock(&slot_list_lock);
295 list_for_each_entry_safe(slot, tmp, &slot_list, list) { 175 list_for_each_entry_safe(slot, tmp, &slot_list, list) {
296 if (slot->root_handle == handle) { 176 if (slot->pci_slot->bus == bus) {
297 list_del(&slot->list); 177 list_del(&slot->list);
298 pbus = slot->pci_slot->bus;
299 pci_destroy_slot(slot->pci_slot); 178 pci_destroy_slot(slot->pci_slot);
300 put_device(&pbus->dev); 179 put_device(&bus->dev);
301 kfree(slot); 180 kfree(slot);
302 } 181 }
303 } 182 }
@@ -332,5 +211,4 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = {
332void __init acpi_pci_slot_init(void) 211void __init acpi_pci_slot_init(void)
333{ 212{
334 dmi_check_system(acpi_pci_slot_dmi_table); 213 dmi_check_system(acpi_pci_slot_dmi_table);
335 acpi_pci_register_driver(&acpi_pci_slot_driver);
336} 214}