aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/manager.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2008-06-27 18:57:17 -0400
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 17:27:07 -0400
commit1f32ca31e7409d37c1b25e5f81840fb184380cdf (patch)
treee587c85b46b04dbbb5987e2a4986ab174f3bd6fa /drivers/pnp/manager.c
parentbbe413b4fc7f791248c7ee00ce7b3778491a3700 (diff)
PNP: convert resource options to single linked list
ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of a device, i.e., the possibilities an OS bus driver has when it assigns I/O port, MMIO, and other resources to the device. PNP used to maintain this "possible resource setting" information in one independent option structure and a list of dependent option structures for each device. Each of these option structures had lists of I/O, memory, IRQ, and DMA resources, for example: dev independent options ind-io0 -> ind-io1 ... ind-mem0 -> ind-mem1 ... ... dependent option set 0 dep0-io0 -> dep0-io1 ... dep0-mem0 -> dep0-mem1 ... ... dependent option set 1 dep1-io0 -> dep1-io1 ... dep1-mem0 -> dep1-mem1 ... ... ... This data structure was designed for ISAPNP, where the OS configures device resource settings by writing directly to configuration registers. The OS can write the registers in arbitrary order much like it writes PCI BARs. However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces that perform device configuration, and it is important to pass the desired settings to those interfaces in the correct order. The OS learns the correct order by using firmware interfaces that return the "current resource settings" and "possible resource settings," but the option structures above doesn't store the ordering information. This patch replaces the independent and dependent lists with a single list of options. For example, a device might have possible resource settings like this: dev options ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ... All the possible settings are in the same list, in the order they come from the firmware "possible resource settings" list. Each entry is tagged with an independent/dependent flag. Dependent entries also have a "set number" and an optional priority value. All dependent entries must be assigned from the same set. For example, the OS can use all the entries from dependent set 0, or all the entries from dependent set 1, but it cannot mix entries from set 0 with entries from set 1. Prior to this patch PNP didn't keep track of the order of this list, and it assigned all independent options first, then all dependent ones. Using the example above, that resulted in a "desired configuration" list like this: ind->io0 -> ind->io1 -> depN-io0 ... instead of the list the firmware expects, which looks like this: ind->io0 -> depN-io0 -> ind-io1 ... Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Acked-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/pnp/manager.c')
-rw-r--r--drivers/pnp/manager.c145
1 files changed, 46 insertions, 99 deletions
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index a20accb5ef8f..b526eaad3f6c 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -3,6 +3,8 @@
3 * 3 *
4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz> 4 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com> 5 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
6 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
7 * Bjorn Helgaas <bjorn.helgaas@hp.com>
6 */ 8 */
7 9
8#include <linux/errno.h> 10#include <linux/errno.h>
@@ -228,102 +230,51 @@ static void pnp_clean_resource_table(struct pnp_dev *dev)
228/** 230/**
229 * pnp_assign_resources - assigns resources to the device based on the specified dependent number 231 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
230 * @dev: pointer to the desired device 232 * @dev: pointer to the desired device
231 * @depnum: the dependent function number 233 * @set: the dependent function number
232 *
233 * Only set depnum to 0 if the device does not have dependent options.
234 */ 234 */
235static int pnp_assign_resources(struct pnp_dev *dev, int depnum) 235static int pnp_assign_resources(struct pnp_dev *dev, int set)
236{ 236{
237 struct pnp_port *port; 237 struct pnp_option *option;
238 struct pnp_mem *mem;
239 struct pnp_irq *irq;
240 struct pnp_dma *dma;
241 int nport = 0, nmem = 0, nirq = 0, ndma = 0; 238 int nport = 0, nmem = 0, nirq = 0, ndma = 0;
239 int ret = 0;
242 240
243 dbg_pnp_show_resources(dev, "before pnp_assign_resources"); 241 dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
244 mutex_lock(&pnp_res_mutex); 242 mutex_lock(&pnp_res_mutex);
245 pnp_clean_resource_table(dev); 243 pnp_clean_resource_table(dev);
246 if (dev->independent) {
247 dev_dbg(&dev->dev, "assigning independent options\n");
248 port = dev->independent->port;
249 mem = dev->independent->mem;
250 irq = dev->independent->irq;
251 dma = dev->independent->dma;
252 while (port) {
253 if (pnp_assign_port(dev, port, nport) < 0)
254 goto fail;
255 nport++;
256 port = port->next;
257 }
258 while (mem) {
259 if (pnp_assign_mem(dev, mem, nmem) < 0)
260 goto fail;
261 nmem++;
262 mem = mem->next;
263 }
264 while (irq) {
265 if (pnp_assign_irq(dev, irq, nirq) < 0)
266 goto fail;
267 nirq++;
268 irq = irq->next;
269 }
270 while (dma) {
271 if (pnp_assign_dma(dev, dma, ndma) < 0)
272 goto fail;
273 ndma++;
274 dma = dma->next;
275 }
276 }
277 244
278 if (depnum) { 245 list_for_each_entry(option, &dev->options, list) {
279 struct pnp_option *dep; 246 if (pnp_option_is_dependent(option) &&
280 int i; 247 pnp_option_set(option) != set)
281 248 continue;
282 dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum); 249
283 for (i = 1, dep = dev->dependent; i < depnum; 250 switch (option->type) {
284 i++, dep = dep->next) 251 case IORESOURCE_IO:
285 if (!dep) 252 ret = pnp_assign_port(dev, &option->u.port, nport++);
286 goto fail; 253 break;
287 port = dep->port; 254 case IORESOURCE_MEM:
288 mem = dep->mem; 255 ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
289 irq = dep->irq; 256 break;
290 dma = dep->dma; 257 case IORESOURCE_IRQ:
291 while (port) { 258 ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
292 if (pnp_assign_port(dev, port, nport) < 0) 259 break;
293 goto fail; 260 case IORESOURCE_DMA:
294 nport++; 261 ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
295 port = port->next; 262 break;
296 } 263 default:
297 while (mem) { 264 ret = -EINVAL;
298 if (pnp_assign_mem(dev, mem, nmem) < 0) 265 break;
299 goto fail;
300 nmem++;
301 mem = mem->next;
302 }
303 while (irq) {
304 if (pnp_assign_irq(dev, irq, nirq) < 0)
305 goto fail;
306 nirq++;
307 irq = irq->next;
308 }
309 while (dma) {
310 if (pnp_assign_dma(dev, dma, ndma) < 0)
311 goto fail;
312 ndma++;
313 dma = dma->next;
314 } 266 }
315 } else if (dev->dependent) 267 if (ret < 0)
316 goto fail; 268 break;
317 269 }
318 mutex_unlock(&pnp_res_mutex);
319 dbg_pnp_show_resources(dev, "after pnp_assign_resources");
320 return 1;
321 270
322fail:
323 pnp_clean_resource_table(dev);
324 mutex_unlock(&pnp_res_mutex); 271 mutex_unlock(&pnp_res_mutex);
325 dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)"); 272 if (ret < 0) {
326 return 0; 273 dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
274 pnp_clean_resource_table(dev);
275 } else
276 dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
277 return ret;
327} 278}
328 279
329/** 280/**
@@ -332,29 +283,25 @@ fail:
332 */ 283 */
333int pnp_auto_config_dev(struct pnp_dev *dev) 284int pnp_auto_config_dev(struct pnp_dev *dev)
334{ 285{
335 struct pnp_option *dep; 286 int i, ret;
336 int i = 1;
337 287
338 if (!pnp_can_configure(dev)) { 288 if (!pnp_can_configure(dev)) {
339 dev_dbg(&dev->dev, "configuration not supported\n"); 289 dev_dbg(&dev->dev, "configuration not supported\n");
340 return -ENODEV; 290 return -ENODEV;
341 } 291 }
342 292
343 if (!dev->dependent) { 293 ret = pnp_assign_resources(dev, 0);
344 if (pnp_assign_resources(dev, 0)) 294 if (ret == 0)
295 return 0;
296
297 for (i = 1; i < dev->num_dependent_sets; i++) {
298 ret = pnp_assign_resources(dev, i);
299 if (ret == 0)
345 return 0; 300 return 0;
346 } else {
347 dep = dev->dependent;
348 do {
349 if (pnp_assign_resources(dev, i))
350 return 0;
351 dep = dep->next;
352 i++;
353 } while (dep);
354 } 301 }
355 302
356 dev_err(&dev->dev, "unable to assign resources\n"); 303 dev_err(&dev->dev, "unable to assign resources\n");
357 return -EBUSY; 304 return ret;
358} 305}
359 306
360/** 307/**