summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2008-06-27 16:57:17 -0600
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 23:27:07 +0200
commit1f32ca31e7409d37c1b25e5f81840fb184380cdf (patch)
treee587c85b46b04dbbb5987e2a4986ab174f3bd6fa
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>
-rw-r--r--drivers/pnp/base.h93
-rw-r--r--drivers/pnp/core.c4
-rw-r--r--drivers/pnp/interface.c75
-rw-r--r--drivers/pnp/isapnp/core.c72
-rw-r--r--drivers/pnp/manager.c145
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c93
-rw-r--r--drivers/pnp/pnpbios/rsparser.c67
-rw-r--r--drivers/pnp/quirks.c290
-rw-r--r--drivers/pnp/resource.c268
-rw-r--r--drivers/pnp/support.c92
-rw-r--r--include/linux/pnp.h6
11 files changed, 571 insertions, 634 deletions
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 360c6385686c..e3fa9a2d9a3d 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,3 +1,8 @@
+/*
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ */
+
extern spinlock_t pnp_lock;
void *pnp_alloc(long size);
@@ -25,8 +30,6 @@ struct pnp_port {
resource_size_t align; /* align boundary */
resource_size_t size; /* size of range */
unsigned char flags; /* port flags */
- unsigned char pad; /* pad */
- struct pnp_port *next; /* next port */
};
#define PNP_IRQ_NR 256
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t;
struct pnp_irq {
pnp_irq_mask_t map; /* bitmap for IRQ lines */
unsigned char flags; /* IRQ flags */
- unsigned char pad; /* pad */
- struct pnp_irq *next; /* next IRQ */
};
struct pnp_dma {
unsigned char map; /* bitmask for DMA channels */
unsigned char flags; /* DMA flags */
- struct pnp_dma *next; /* next port */
};
struct pnp_mem {
@@ -51,44 +51,91 @@ struct pnp_mem {
resource_size_t align; /* align boundary */
resource_size_t size; /* size of range */
unsigned char flags; /* memory flags */
- unsigned char pad; /* pad */
- struct pnp_mem *next; /* next memory resource */
};
+#define PNP_OPTION_DEPENDENT 0x80000000
+#define PNP_OPTION_SET_MASK 0xffff
+#define PNP_OPTION_SET_SHIFT 12
+#define PNP_OPTION_PRIORITY_MASK 0xfff
+#define PNP_OPTION_PRIORITY_SHIFT 0
+
#define PNP_RES_PRIORITY_PREFERRED 0
#define PNP_RES_PRIORITY_ACCEPTABLE 1
#define PNP_RES_PRIORITY_FUNCTIONAL 2
-#define PNP_RES_PRIORITY_INVALID 65535
+#define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK
struct pnp_option {
- unsigned short priority; /* priority */
- struct pnp_port *port; /* first port */
- struct pnp_irq *irq; /* first IRQ */
- struct pnp_dma *dma; /* first DMA */
- struct pnp_mem *mem; /* first memory resource */
- struct pnp_option *next; /* used to chain dependent resources */
+ struct list_head list;
+ unsigned int flags; /* independent/dependent, set, priority */
+
+ unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */
+ union {
+ struct pnp_port port;
+ struct pnp_irq irq;
+ struct pnp_dma dma;
+ struct pnp_mem mem;
+ } u;
};
-struct pnp_option *pnp_build_option(int priority);
-struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
-struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
- int priority);
-int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
pnp_irq_mask_t *map, unsigned char flags);
-int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
unsigned char map, unsigned char flags);
-int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
resource_size_t min, resource_size_t max,
resource_size_t align, resource_size_t size,
unsigned char flags);
-int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
resource_size_t min, resource_size_t max,
resource_size_t align, resource_size_t size,
unsigned char flags);
+
+static inline int pnp_option_is_dependent(struct pnp_option *option)
+{
+ return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0;
+}
+
+static inline unsigned int pnp_option_set(struct pnp_option *option)
+{
+ return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK;
+}
+
+static inline unsigned int pnp_option_priority(struct pnp_option *option)
+{
+ return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) &
+ PNP_OPTION_PRIORITY_MASK;
+}
+
+static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev,
+ int priority)
+{
+ unsigned int flags;
+
+ if (priority > PNP_RES_PRIORITY_FUNCTIONAL) {
+ dev_warn(&dev->dev, "invalid dependent option priority %d "
+ "clipped to %d", priority,
+ PNP_RES_PRIORITY_INVALID);
+ priority = PNP_RES_PRIORITY_INVALID;
+ }
+
+ flags = PNP_OPTION_DEPENDENT |
+ ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) <<
+ PNP_OPTION_SET_SHIFT) |
+ ((priority & PNP_OPTION_PRIORITY_MASK) <<
+ PNP_OPTION_PRIORITY_SHIFT);
+
+ dev->num_dependent_sets++;
+
+ return flags;
+}
+
+char *pnp_option_priority_name(struct pnp_option *option);
+void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option);
+
void pnp_init_resources(struct pnp_dev *dev);
void pnp_fixup_device(struct pnp_dev *dev);
-void pnp_free_option(struct pnp_option *option);
+void pnp_free_options(struct pnp_dev *dev);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 7182da92aec3..a411582bcd72 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -118,10 +118,9 @@ static void pnp_release_device(struct device *dmdev)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
- pnp_free_option(dev->independent);
- pnp_free_option(dev->dependent);
pnp_free_ids(dev);
pnp_free_resources(dev);
+ pnp_free_options(dev);
kfree(dev);
}
@@ -135,6 +134,7 @@ struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid
return NULL;
INIT_LIST_HEAD(&dev->resources);
+ INIT_LIST_HEAD(&dev->options);
dev->protocol = protocol;
dev->number = id;
dev->dma_mask = DMA_24BIT_MASK;
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 7a9fb5544b80..a876ecf7028c 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -3,6 +3,8 @@
*
* Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/pnp.h>
@@ -184,39 +186,22 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
}
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
- struct pnp_option *option, int dep)
+ struct pnp_option *option)
{
- char *s;
- struct pnp_port *port;
- struct pnp_irq *irq;
- struct pnp_dma *dma;
- struct pnp_mem *mem;
-
- if (dep) {
- switch (option->priority) {
- case PNP_RES_PRIORITY_PREFERRED:
- s = "preferred";
- break;
- case PNP_RES_PRIORITY_ACCEPTABLE:
- s = "acceptable";
- break;
- case PNP_RES_PRIORITY_FUNCTIONAL:
- s = "functional";
- break;
- default:
- s = "invalid";
- }
- pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
+ switch (option->type) {
+ case IORESOURCE_IO:
+ pnp_print_port(buffer, space, &option->u.port);
+ break;
+ case IORESOURCE_MEM:
+ pnp_print_mem(buffer, space, &option->u.mem);
+ break;
+ case IORESOURCE_IRQ:
+ pnp_print_irq(buffer, space, &option->u.irq);
+ break;
+ case IORESOURCE_DMA:
+ pnp_print_dma(buffer, space, &option->u.dma);
+ break;
}
-
- for (port = option->port; port; port = port->next)
- pnp_print_port(buffer, space, port);
- for (irq = option->irq; irq; irq = irq->next)
- pnp_print_irq(buffer, space, irq);
- for (dma = option->dma; dma; dma = dma->next)
- pnp_print_dma(buffer, space, dma);
- for (mem = option->mem; mem; mem = mem->next)
- pnp_print_mem(buffer, space, mem);
}
static ssize_t pnp_show_options(struct device *dmdev,
@@ -224,9 +209,9 @@ static ssize_t pnp_show_options(struct device *dmdev,
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
pnp_info_buffer_t *buffer;
- struct pnp_option *independent = dev->independent;
- struct pnp_option *dependent = dev->dependent;
- int ret, dep = 1;
+ struct pnp_option *option;
+ int ret, dep = 0, set = 0;
+ char *indent;
buffer = pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
@@ -235,14 +220,24 @@ static ssize_t pnp_show_options(struct device *dmdev,
buffer->len = PAGE_SIZE;
buffer->buffer = buf;
buffer->curr = buffer->buffer;
- if (independent)
- pnp_print_option(buffer, "", independent, 0);
- while (dependent) {
- pnp_print_option(buffer, " ", dependent, dep);
- dependent = dependent->next;
- dep++;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option)) {
+ indent = " ";
+ if (!dep || pnp_option_set(option) != set) {
+ set = pnp_option_set(option);
+ dep = 1;
+ pnp_printf(buffer, "Dependent: %02i - "
+ "Priority %s\n", set,
+ pnp_option_priority_name(option));
+ }
+ } else {
+ dep = 0;
+ indent = "";
+ }
+ pnp_print_option(buffer, indent, option);
}
+
ret = (buffer->curr - buf);
kfree(buffer);
return ret;
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 53cc4d6133e6..101a835e8759 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -429,7 +429,7 @@ static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
* Add IRQ resource to resources list.
*/
static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[3];
@@ -446,27 +446,27 @@ static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
if (size > 2)
flags = tmp[2];
- pnp_register_irq_resource(dev, option, &map, flags);
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
/*
* Add DMA resource to resources list.
*/
static void __init isapnp_parse_dma_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[2];
isapnp_peek(tmp, size);
- pnp_register_dma_resource(dev, option, tmp[0], tmp[1]);
+ pnp_register_dma_resource(dev, option_flags, tmp[0], tmp[1]);
}
/*
* Add port resource to resources list.
*/
static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[7];
@@ -479,14 +479,15 @@ static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
align = tmp[5];
len = tmp[6];
flags = tmp[0] ? IORESOURCE_IO_16BIT_ADDR : 0;
- pnp_register_port_resource(dev, option, min, max, align, len, flags);
+ pnp_register_port_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add fixed port resource to resources list.
*/
static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[3];
@@ -495,7 +496,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
isapnp_peek(tmp, size);
base = (tmp[1] << 8) | tmp[0];
len = tmp[2];
- pnp_register_port_resource(dev, option, base, base, 0, len,
+ pnp_register_port_resource(dev, option_flags, base, base, 0, len,
IORESOURCE_IO_FIXED);
}
@@ -503,7 +504,7 @@ static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
* Add memory resource to resources list.
*/
static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[9];
@@ -516,14 +517,15 @@ static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
align = (tmp[6] << 8) | tmp[5];
len = ((tmp[8] << 8) | tmp[7]) << 8;
flags = tmp[0];
- pnp_register_mem_resource(dev, option, min, max, align, len, flags);
+ pnp_register_mem_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add 32-bit memory resource to resources list.
*/
static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[17];
@@ -536,14 +538,15 @@ static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
len = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
flags = tmp[0];
- pnp_register_mem_resource(dev, option, min, max, align, len, flags);
+ pnp_register_mem_resource(dev, option_flags,
+ min, max, align, len, flags);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
int size)
{
unsigned char tmp[9];
@@ -554,7 +557,7 @@ static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
base = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
len = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
flags = tmp[0];
- pnp_register_mem_resource(dev, option, base, base, 0, len, flags);
+ pnp_register_mem_resource(dev, option_flags, base, base, 0, len, flags);
}
/*
@@ -584,18 +587,14 @@ static int __init isapnp_create_device(struct pnp_card *card,
{
int number = 0, skip = 0, priority, compat = 0;
unsigned char type, tmp[17];
- struct pnp_option *option, *option_independent;
+ unsigned int option_flags;
struct pnp_dev *dev;
u32 eisa_id;
char id[8];
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
- option_independent = option = pnp_register_independent_option(dev);
- if (!option) {
- kfree(dev);
- return 1;
- }
+ option_flags = 0;
pnp_add_card_device(card, dev);
while (1) {
@@ -612,12 +611,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
return 1;
size = 0;
skip = 0;
- option = pnp_register_independent_option(dev);
- option_independent = option;
- if (!option) {
- kfree(dev);
- return 1;
- }
+ option_flags = 0;
pnp_add_card_device(card, dev);
} else {
skip = 1;
@@ -638,13 +632,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_IRQ:
if (size < 2 || size > 3)
goto __skip;
- isapnp_parse_irq_resource(dev, option, size);
+ isapnp_parse_irq_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_DMA:
if (size != 2)
goto __skip;
- isapnp_parse_dma_resource(dev, option, size);
+ isapnp_parse_dma_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_STARTDEP:
@@ -656,29 +650,24 @@ static int __init isapnp_create_device(struct pnp_card *card,
priority = tmp[0];
size = 0;
}
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return 1;
+ option_flags = pnp_new_dependent_set(dev, priority);
break;
case _STAG_ENDDEP:
if (size != 0)
goto __skip;
- if (option_independent == option)
- dev_warn(&dev->dev, "missing "
- "_STAG_STARTDEP tag\n");
- option = option_independent;
- dev_dbg(&dev->dev, "end dependent options\n");
+ option_flags = 0;
break;
case _STAG_IOPORT:
if (size != 7)
goto __skip;
- isapnp_parse_port_resource(dev, option, size);
+ isapnp_parse_port_resource(dev, option_flags, size);
size = 0;
break;
case _STAG_FIXEDIO:
if (size != 3)
goto __skip;
- isapnp_parse_fixed_port_resource(dev, option, size);
+ isapnp_parse_fixed_port_resource(dev, option_flags,
+ size);
size = 0;
break;
case _STAG_VENDOR:
@@ -686,7 +675,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEMRANGE:
if (size != 9)
goto __skip;
- isapnp_parse_mem_resource(dev, option, size);
+ isapnp_parse_mem_resource(dev, option_flags, size);
size = 0;
break;
case _LTAG_ANSISTR:
@@ -701,13 +690,14 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEM32RANGE:
if (size != 17)
goto __skip;
- isapnp_parse_mem32_resource(dev, option, size);
+ isapnp_parse_mem32_resource(dev, option_flags, size);
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 9)
goto __skip;
- isapnp_parse_fixed_mem32_resource(dev, option, size);
+ isapnp_parse_fixed_mem32_resource(dev, option_flags,
+ size);
size = 0;
break;
case _STAG_END:
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 @@
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
+ * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*/
#include <linux/errno.h>
@@ -228,102 +230,51 @@ static void pnp_clean_resource_table(struct pnp_dev *dev)
/**
* pnp_assign_resources - assigns resources to the device based on the specified dependent number
* @dev: pointer to the desired device
- * @depnum: the dependent function number
- *
- * Only set depnum to 0 if the device does not have dependent options.
+ * @set: the dependent function number
*/
-static int pnp_assign_resources(struct pnp_dev *dev, int depnum)
+static int pnp_assign_resources(struct pnp_dev *dev, int set)
{
- struct pnp_port *port;
- struct pnp_mem *mem;
- struct pnp_irq *irq;
- struct pnp_dma *dma;
+ struct pnp_option *option;
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
+ int ret = 0;
- dbg_pnp_show_resources(dev, "before pnp_assign_resources");
+ dev_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
mutex_lock(&pnp_res_mutex);
pnp_clean_resource_table(dev);
- if (dev->independent) {
- dev_dbg(&dev->dev, "assigning independent options\n");
- port = dev->independent->port;
- mem = dev->independent->mem;
- irq = dev->independent->irq;
- dma = dev->independent->dma;
- while (port) {
- if (pnp_assign_port(dev, port, nport) < 0)
- goto fail;
- nport++;
- port = port->next;
- }
- while (mem) {
- if (pnp_assign_mem(dev, mem, nmem) < 0)
- goto fail;
- nmem++;
- mem = mem->next;
- }
- while (irq) {
- if (pnp_assign_irq(dev, irq, nirq) < 0)
- goto fail;
- nirq++;
- irq = irq->next;
- }
- while (dma) {
- if (pnp_assign_dma(dev, dma, ndma) < 0)
- goto fail;
- ndma++;
- dma = dma->next;
- }
- }
- if (depnum) {
- struct pnp_option *dep;
- int i;
-
- dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
- for (i = 1, dep = dev->dependent; i < depnum;
- i++, dep = dep->next)
- if (!dep)
- goto fail;
- port = dep->port;
- mem = dep->mem;
- irq = dep->irq;
- dma = dep->dma;
- while (port) {
- if (pnp_assign_port(dev, port, nport) < 0)
- goto fail;
- nport++;
- port = port->next;
- }
- while (mem) {
- if (pnp_assign_mem(dev, mem, nmem) < 0)
- goto fail;
- nmem++;
- mem = mem->next;
- }
- while (irq) {
- if (pnp_assign_irq(dev, irq, nirq) < 0)
- goto fail;
- nirq++;
- irq = irq->next;
- }
- while (dma) {
- if (pnp_assign_dma(dev, dma, ndma) < 0)
- goto fail;
- ndma++;
- dma = dma->next;
+ list_for_each_entry(option, &dev->options, list) {
+ if (pnp_option_is_dependent(option) &&
+ pnp_option_set(option) != set)
+ continue;
+
+ switch (option->type) {
+ case IORESOURCE_IO:
+ ret = pnp_assign_port(dev, &option->u.port, nport++);
+ break;
+ case IORESOURCE_MEM:
+ ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
+ break;
+ case IORESOURCE_IRQ:
+ ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
+ break;
+ case IORESOURCE_DMA:
+ ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- } else if (dev->dependent)
- goto fail;
-
- mutex_unlock(&pnp_res_mutex);
- dbg_pnp_show_resources(dev, "after pnp_assign_resources");
- return 1;
+ if (ret < 0)
+ break;
+ }
-fail:
- pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
- dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
- return 0;
+ if (ret < 0) {
+ dev_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
+ pnp_clean_resource_table(dev);
+ } else
+ dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
+ return ret;
}
/**
@@ -332,29 +283,25 @@ fail:
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
- struct pnp_option *dep;
- int i = 1;
+ int i, ret;
if (!pnp_can_configure(dev)) {
dev_dbg(&dev->dev, "configuration not supported\n");
return -ENODEV;
}
- if (!dev->dependent) {
- if (pnp_assign_resources(dev, 0))
+ ret = pnp_assign_resources(dev, 0);
+ if (ret == 0)
+ return 0;
+
+ for (i = 1; i < dev->num_dependent_sets; i++) {
+ ret = pnp_assign_resources(dev, i);
+ if (ret == 0)
return 0;
- } else {
- dep = dev->dependent;
- do {
- if (pnp_assign_resources(dev, i))
- return 0;
- dep = dep->next;
- i++;
- } while (dep);
}
dev_err(&dev->dev, "unable to assign resources\n");
- return -EBUSY;
+ return ret;
}
/**
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index e114b3d2b933..c2f59f4d20bc 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -407,7 +407,7 @@ int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
}
static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_dma *p)
{
int i;
@@ -420,11 +420,11 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
map |= 1 << p->channels[i];
flags = dma_flags(p->type, p->bus_master, p->transfer);
- pnp_register_dma_resource(dev, option, map, flags);
+ pnp_register_dma_resource(dev, option_flags, map, flags);
}
static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_irq *p)
{
int i;
@@ -440,11 +440,11 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
__set_bit(p->interrupts[i], map.bits);
flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(dev, option, &map, flags);
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_extended_irq *p)
{
int i;
@@ -467,11 +467,11 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
}
flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(dev, option, &map, flags);
+ pnp_register_irq_resource(dev, option_flags, &map, flags);
}
static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_io *io)
{
unsigned char flags = 0;
@@ -481,23 +481,23 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
if (io->io_decode == ACPI_DECODE_16)
flags = IORESOURCE_IO_16BIT_ADDR;
- pnp_register_port_resource(dev, option, io->minimum, io->maximum,
+ pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum,
io->alignment, io->address_length, flags);
}
static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_fixed_io *io)
{
if (io->address_length == 0)
return;
- pnp_register_port_resource(dev, option, io->address, io->address, 0,
- io->address_length, IORESOURCE_IO_FIXED);
+ pnp_register_port_resource(dev, option_flags, io->address, io->address,
+ 0, io->address_length, IORESOURCE_IO_FIXED);
}
static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_memory24 *p)
{
unsigned char flags = 0;
@@ -507,12 +507,12 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
if (p->write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option, p->minimum, p->maximum,
+ pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
p->alignment, p->address_length, flags);
}
static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_memory32 *p)
{
unsigned char flags = 0;
@@ -522,12 +522,12 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
if (p->write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option, p->minimum, p->maximum,
+ pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum,
p->alignment, p->address_length, flags);
}
static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource_fixed_memory32 *p)
{
unsigned char flags = 0;
@@ -537,12 +537,12 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
if (p->write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option, p->address, p->address,
+ pnp_register_mem_resource(dev, option_flags, p->address, p->address,
0, p->address_length, flags);
}
static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
- struct pnp_option *option,
+ unsigned int option_flags,
struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
@@ -562,18 +562,18 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
if (p->resource_type == ACPI_MEMORY_RANGE) {
if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option, p->minimum, p->minimum,
- 0, p->address_length, flags);
+ pnp_register_mem_resource(dev, option_flags, p->minimum,
+ p->minimum, 0, p->address_length,
+ flags);
} else if (p->resource_type == ACPI_IO_RANGE)
- pnp_register_port_resource(dev, option, p->minimum, p->minimum,
- 0, p->address_length,
+ pnp_register_port_resource(dev, option_flags, p->minimum,
+ p->minimum, 0, p->address_length,
IORESOURCE_IO_FIXED);
}
struct acpipnp_parse_option_s {
- struct pnp_option *option;
- struct pnp_option *option_independent;
struct pnp_dev *dev;
+ unsigned int option_flags;
};
static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
@@ -582,15 +582,15 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
int priority;
struct acpipnp_parse_option_s *parse_data = data;
struct pnp_dev *dev = parse_data->dev;
- struct pnp_option *option = parse_data->option;
+ unsigned int option_flags = parse_data->option_flags;
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnpacpi_parse_irq_option(dev, option, &res->data.irq);
+ pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq);
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(dev, option, &res->data.dma);
+ pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -610,31 +610,19 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
priority = PNP_RES_PRIORITY_INVALID;
break;
}
- /* TBD: Consider performance/robustness bits */
- option = pnp_register_dependent_option(dev, priority);
- if (!option)
- return AE_ERROR;
- parse_data->option = option;
+ parse_data->option_flags = pnp_new_dependent_set(dev, priority);
break;
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- /*only one EndDependentFn is allowed */
- if (!parse_data->option_independent) {
- dev_warn(&dev->dev, "more than one EndDependentFn "
- "in _PRS\n");
- return AE_ERROR;
- }
- parse_data->option = parse_data->option_independent;
- parse_data->option_independent = NULL;
- dev_dbg(&dev->dev, "end dependent options\n");
+ parse_data->option_flags = 0;
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_port_option(dev, option, &res->data.io);
+ pnpacpi_parse_port_option(dev, option_flags, &res->data.io);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_fixed_port_option(dev, option,
+ pnpacpi_parse_fixed_port_option(dev, option_flags,
&res->data.fixed_io);
break;
@@ -643,29 +631,31 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_mem24_option(dev, option, &res->data.memory24);
+ pnpacpi_parse_mem24_option(dev, option_flags,
+ &res->data.memory24);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_mem32_option(dev, option, &res->data.memory32);
+ pnpacpi_parse_mem32_option(dev, option_flags,
+ &res->data.memory32);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_fixed_mem32_option(dev, option,
+ pnpacpi_parse_fixed_mem32_option(dev, option_flags,
&res->data.fixed_memory32);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_address_option(dev, option, res);
+ pnpacpi_parse_address_option(dev, option_flags, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnpacpi_parse_ext_irq_option(dev, option,
+ pnpacpi_parse_ext_irq_option(dev, option_flags,
&res->data.extended_irq);
break;
@@ -689,12 +679,9 @@ int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
dev_dbg(&d