diff options
author | Alexander Chiang <achiang@hp.com> | 2009-06-10 15:55:30 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-06-17 23:22:16 -0400 |
commit | 499650de6906722184b639989b47227a362b62f8 (patch) | |
tree | f0920b27dc659fb976f3ac2ca77bca6a386cd6c0 | |
parent | c22d7f5a389dad15de448b142f44e4000b3426f0 (diff) |
ACPI: eviscerate pci_bind.c
Now that we can dynamically convert an ACPI CA handle to a
struct pci_dev at runtime, there's no need to statically bind
them during boot.
acpi_pci_bind/unbind are vastly simplified, and are only used
to evaluate _PRT methods on P2P bridges and non-bridge children.
This patch also changes the time-space tradeoff ever so slightly.
Looking up the ACPI-PCI binding is never in the performance path, and by
eliminating this caching, we save 24 bytes for each _ADR device in the
ACPI namespace.
This patch lays further groundwork to eventually eliminate
the acpi_driver_ops.bind callback.
Signed-off-by: Alex Chiang <achiang@hp.com>
Acked-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/pci_bind.c | 245 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 2 | ||||
-rw-r--r-- | include/acpi/acpi_drivers.h | 3 |
3 files changed, 39 insertions, 211 deletions
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index c283c29662a7..703d2a3e8012 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c | |||
@@ -24,12 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/module.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/types.h> | 27 | #include <linux/types.h> |
30 | #include <linux/proc_fs.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/pm.h> | ||
33 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
34 | #include <linux/acpi.h> | 29 | #include <linux/acpi.h> |
35 | #include <acpi/acpi_bus.h> | 30 | #include <acpi/acpi_bus.h> |
@@ -111,238 +106,72 @@ EXPORT_SYMBOL(acpi_get_pci_id); | |||
111 | 106 | ||
112 | static int acpi_pci_unbind(struct acpi_device *device) | 107 | static int acpi_pci_unbind(struct acpi_device *device) |
113 | { | 108 | { |
114 | int result = 0; | 109 | struct pci_dev *dev; |
115 | acpi_status status; | ||
116 | struct acpi_pci_data *data; | ||
117 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
118 | |||
119 | |||
120 | if (!device || !device->parent) | ||
121 | return -EINVAL; | ||
122 | |||
123 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | ||
124 | if (ACPI_FAILURE(status)) | ||
125 | return -ENODEV; | ||
126 | |||
127 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", | ||
128 | (char *) buffer.pointer)); | ||
129 | kfree(buffer.pointer); | ||
130 | 110 | ||
131 | status = | 111 | dev = acpi_get_pci_dev(device->handle); |
132 | acpi_get_data(device->handle, acpi_pci_data_handler, | 112 | if (!dev) |
133 | (void **)&data); | 113 | return 0; |
134 | if (ACPI_FAILURE(status)) { | ||
135 | result = -ENODEV; | ||
136 | goto end; | ||
137 | } | ||
138 | 114 | ||
139 | status = acpi_detach_data(device->handle, acpi_pci_data_handler); | 115 | if (dev->subordinate) |
140 | if (ACPI_FAILURE(status)) { | 116 | acpi_pci_irq_del_prt(pci_domain_nr(dev->bus), |
141 | ACPI_EXCEPTION((AE_INFO, status, | 117 | dev->subordinate->number); |
142 | "Unable to detach data from device %s", | ||
143 | acpi_device_bid(device))); | ||
144 | result = -ENODEV; | ||
145 | goto end; | ||
146 | } | ||
147 | if (data->dev->subordinate) { | ||
148 | acpi_pci_irq_del_prt(data->id.segment, data->bus->number); | ||
149 | } | ||
150 | pci_dev_put(data->dev); | ||
151 | kfree(data); | ||
152 | 118 | ||
153 | end: | 119 | pci_dev_put(dev); |
154 | return result; | 120 | return 0; |
155 | } | 121 | } |
156 | 122 | ||
157 | static int acpi_pci_bind(struct acpi_device *device) | 123 | static int acpi_pci_bind(struct acpi_device *device) |
158 | { | 124 | { |
159 | int result = 0; | ||
160 | acpi_status status; | 125 | acpi_status status; |
161 | struct acpi_pci_data *data; | ||
162 | struct acpi_pci_data *pdata; | ||
163 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
164 | acpi_handle handle; | 126 | acpi_handle handle; |
127 | unsigned char bus; | ||
128 | struct pci_dev *dev; | ||
165 | 129 | ||
166 | if (!device || !device->parent) | 130 | dev = acpi_get_pci_dev(device->handle); |
167 | return -EINVAL; | 131 | if (!dev) |
168 | 132 | return 0; | |
169 | data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); | ||
170 | if (!data) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | ||
174 | if (ACPI_FAILURE(status)) { | ||
175 | kfree(data); | ||
176 | return -ENODEV; | ||
177 | } | ||
178 | |||
179 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", | ||
180 | (char *)buffer.pointer)); | ||
181 | |||
182 | /* | ||
183 | * Segment & Bus | ||
184 | * ------------- | ||
185 | * These are obtained via the parent device's ACPI-PCI context. | ||
186 | */ | ||
187 | status = acpi_get_data(device->parent->handle, acpi_pci_data_handler, | ||
188 | (void **)&pdata); | ||
189 | if (ACPI_FAILURE(status) || !pdata || !pdata->bus) { | ||
190 | ACPI_EXCEPTION((AE_INFO, status, | ||
191 | "Invalid ACPI-PCI context for parent device %s", | ||
192 | acpi_device_bid(device->parent))); | ||
193 | result = -ENODEV; | ||
194 | goto end; | ||
195 | } | ||
196 | data->id.segment = pdata->id.segment; | ||
197 | data->id.bus = pdata->bus->number; | ||
198 | |||
199 | /* | ||
200 | * Device & Function | ||
201 | * ----------------- | ||
202 | * These are simply obtained from the device's _ADR method. Note | ||
203 | * that a value of zero is valid. | ||
204 | */ | ||
205 | data->id.device = device->pnp.bus_address >> 16; | ||
206 | data->id.function = device->pnp.bus_address & 0xFFFF; | ||
207 | |||
208 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", | ||
209 | data->id.segment, data->id.bus, data->id.device, | ||
210 | data->id.function)); | ||
211 | |||
212 | /* | ||
213 | * TBD: Support slot devices (e.g. function=0xFFFF). | ||
214 | */ | ||
215 | |||
216 | /* | ||
217 | * Locate PCI Device | ||
218 | * ----------------- | ||
219 | * Locate matching device in PCI namespace. If it doesn't exist | ||
220 | * this typically means that the device isn't currently inserted | ||
221 | * (e.g. docking station, port replicator, etc.). | ||
222 | */ | ||
223 | data->dev = pci_get_slot(pdata->bus, | ||
224 | PCI_DEVFN(data->id.device, data->id.function)); | ||
225 | if (!data->dev) { | ||
226 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
227 | "Device %04x:%02x:%02x.%d not present in PCI namespace\n", | ||
228 | data->id.segment, data->id.bus, | ||
229 | data->id.device, data->id.function)); | ||
230 | result = -ENODEV; | ||
231 | goto end; | ||
232 | } | ||
233 | if (!data->dev->bus) { | ||
234 | printk(KERN_ERR PREFIX | ||
235 | "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", | ||
236 | data->id.segment, data->id.bus, | ||
237 | data->id.device, data->id.function); | ||
238 | result = -ENODEV; | ||
239 | goto end; | ||
240 | } | ||
241 | 133 | ||
242 | /* | 134 | /* |
243 | * PCI Bridge? | 135 | * Install the 'bind' function to facilitate callbacks for |
244 | * ----------- | 136 | * children of the P2P bridge. |
245 | * If so, set the 'bus' field and install the 'bind' function to | ||
246 | * facilitate callbacks for all of its children. | ||
247 | */ | 137 | */ |
248 | if (data->dev->subordinate) { | 138 | if (dev->subordinate) { |
249 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 139 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
250 | "Device %04x:%02x:%02x.%d is a PCI bridge\n", | 140 | "Device %04x:%02x:%02x.%d is a PCI bridge\n", |
251 | data->id.segment, data->id.bus, | 141 | pci_domain_nr(dev->bus), dev->bus->number, |
252 | data->id.device, data->id.function)); | 142 | PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn))); |
253 | data->bus = data->dev->subordinate; | ||
254 | device->ops.bind = acpi_pci_bind; | 143 | device->ops.bind = acpi_pci_bind; |
255 | device->ops.unbind = acpi_pci_unbind; | 144 | device->ops.unbind = acpi_pci_unbind; |
256 | } | 145 | } |
257 | 146 | ||
258 | /* | 147 | /* |
259 | * Attach ACPI-PCI Context | 148 | * Evaluate and parse _PRT, if exists. This code allows parsing of |
260 | * ----------------------- | 149 | * _PRT objects within the scope of non-bridge devices. Note that |
261 | * Thus binding the ACPI and PCI devices. | 150 | * _PRTs within the scope of a PCI bridge assume the bridge's |
262 | */ | 151 | * subordinate bus number. |
263 | status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); | ||
264 | if (ACPI_FAILURE(status)) { | ||
265 | ACPI_EXCEPTION((AE_INFO, status, | ||
266 | "Unable to attach ACPI-PCI context to device %s", | ||
267 | acpi_device_bid(device))); | ||
268 | result = -ENODEV; | ||
269 | goto end; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * PCI Routing Table | ||
274 | * ----------------- | ||
275 | * Evaluate and parse _PRT, if exists. This code is independent of | ||
276 | * PCI bridges (above) to allow parsing of _PRT objects within the | ||
277 | * scope of non-bridge devices. Note that _PRTs within the scope of | ||
278 | * a PCI bridge assume the bridge's subordinate bus number. | ||
279 | * | 152 | * |
280 | * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? | 153 | * TBD: Can _PRTs exist within the scope of non-bridge PCI devices? |
281 | */ | 154 | */ |
282 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); | 155 | status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); |
283 | if (ACPI_SUCCESS(status)) { | 156 | if (ACPI_FAILURE(status)) |
284 | if (data->bus) /* PCI-PCI bridge */ | 157 | goto out; |
285 | acpi_pci_irq_add_prt(device->handle, data->id.segment, | ||
286 | data->bus->number); | ||
287 | else /* non-bridge PCI device */ | ||
288 | acpi_pci_irq_add_prt(device->handle, data->id.segment, | ||
289 | data->id.bus); | ||
290 | } | ||
291 | |||
292 | end: | ||
293 | kfree(buffer.pointer); | ||
294 | if (result) { | ||
295 | pci_dev_put(data->dev); | ||
296 | kfree(data); | ||
297 | } | ||
298 | return result; | ||
299 | } | ||
300 | 158 | ||
301 | int | 159 | if (dev->subordinate) |
302 | acpi_pci_bind_root(struct acpi_device *device, | 160 | bus = dev->subordinate->number; |
303 | struct acpi_pci_id *id, struct pci_bus *bus) | 161 | else |
304 | { | 162 | bus = dev->bus->number; |
305 | int result = 0; | ||
306 | acpi_status status; | ||
307 | struct acpi_pci_data *data = NULL; | ||
308 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
309 | 163 | ||
310 | if (!device || !id || !bus) { | 164 | acpi_pci_irq_add_prt(device->handle, pci_domain_nr(dev->bus), bus); |
311 | return -EINVAL; | ||
312 | } | ||
313 | 165 | ||
314 | data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); | 166 | out: |
315 | if (!data) | 167 | pci_dev_put(dev); |
316 | return -ENOMEM; | 168 | return 0; |
169 | } | ||
317 | 170 | ||
318 | data->id = *id; | 171 | int acpi_pci_bind_root(struct acpi_device *device) |
319 | data->bus = bus; | 172 | { |
320 | device->ops.bind = acpi_pci_bind; | 173 | device->ops.bind = acpi_pci_bind; |
321 | device->ops.unbind = acpi_pci_unbind; | 174 | device->ops.unbind = acpi_pci_unbind; |
322 | 175 | ||
323 | status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); | 176 | return 0; |
324 | if (ACPI_FAILURE(status)) { | ||
325 | kfree (data); | ||
326 | return -ENODEV; | ||
327 | } | ||
328 | |||
329 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " | ||
330 | "%04x:%02x\n", (char *)buffer.pointer, | ||
331 | id->segment, id->bus)); | ||
332 | |||
333 | status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); | ||
334 | if (ACPI_FAILURE(status)) { | ||
335 | ACPI_EXCEPTION((AE_INFO, status, | ||
336 | "Unable to attach ACPI-PCI context to device %s", | ||
337 | (char *)buffer.pointer)); | ||
338 | result = -ENODEV; | ||
339 | goto end; | ||
340 | } | ||
341 | |||
342 | end: | ||
343 | kfree(buffer.pointer); | ||
344 | if (result != 0) | ||
345 | kfree(data); | ||
346 | |||
347 | return result; | ||
348 | } | 177 | } |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index e5099919e574..f23fcc5c9674 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
@@ -603,7 +603,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) | |||
603 | * ----------------------- | 603 | * ----------------------- |
604 | * Thus binding the ACPI and PCI devices. | 604 | * Thus binding the ACPI and PCI devices. |
605 | */ | 605 | */ |
606 | result = acpi_pci_bind_root(device, &root->id, root->bus); | 606 | result = acpi_pci_bind_root(device); |
607 | if (result) | 607 | if (result) |
608 | goto end; | 608 | goto end; |
609 | 609 | ||
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index dbe3989952ee..2740a2894837 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h | |||
@@ -100,8 +100,7 @@ struct pci_bus; | |||
100 | 100 | ||
101 | struct pci_dev *acpi_get_pci_dev(acpi_handle); | 101 | struct pci_dev *acpi_get_pci_dev(acpi_handle); |
102 | acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id); | 102 | acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id); |
103 | int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, | 103 | int acpi_pci_bind_root(struct acpi_device *device); |
104 | struct pci_bus *bus); | ||
105 | 104 | ||
106 | /* Arch-defined function to add a bus to the system */ | 105 | /* Arch-defined function to add a bus to the system */ |
107 | 106 | ||