summaryrefslogtreecommitdiff
path: root/drivers/pnp
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2008-06-27 16:57:14 -0600
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 23:27:07 +0200
commitd5ebde6ef5c2d51828f975a81d7d0e58bccfd833 (patch)
tree04563a7350dfc83784c77c16d0c3d49120dc05ad /drivers/pnp
parent2d29a7a794c5bae982955cd5dd0a76e766e57f39 (diff)
PNP: support optional IRQ resources
This patch adds an IORESOURCE_IRQ_OPTIONAL flag for use when assigning resources to a device. If the flag is set and we are unable to assign an IRQ to the device, we can leave the IRQ disabled but allow the overall resource allocation to succeed. Some devices request an IRQ, but can run without an IRQ (possibly with degraded performance). This flag lets us run the device without the IRQ instead of just leaving the device disabled. This is a reimplementation of this previous change by Rene Herman <rene.herman@gmail.com>: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3b73a223661ed137c5d3d2635f954382e94f5a43 I reimplemented this for two reasons: - to prepare for converting all resource options into a single linked list, as opposed to the per-resource-type lists we have now, and - to preserve the order and number of resource options. In PNPBIOS and ACPI, we configure a device by giving firmware a list of resource assignments. It is important that this list has exactly the same number of resources, in the same order, as the "template" list we got from the firmware in the first place. The problem of a sound card MPU401 being left disabled for want of an IRQ was reported by Uwe Bugla <uwe.bugla@gmx.de>. 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')
-rw-r--r--drivers/pnp/interface.c2
-rw-r--r--drivers/pnp/manager.c9
-rw-r--r--drivers/pnp/quirks.c71
3 files changed, 38 insertions, 44 deletions
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index b09f67de13d0..7a9fb5544b80 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -90,6 +90,8 @@ static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
pnp_printf(buffer, " High-Level");
if (irq->flags & IORESOURCE_IRQ_LOWLEVEL)
pnp_printf(buffer, " Low-Level");
+ if (irq->flags & IORESOURCE_IRQ_OPTIONAL)
+ pnp_printf(buffer, " (optional)");
pnp_printf(buffer, "\n");
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 7ea9e1e28003..a20accb5ef8f 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -153,6 +153,15 @@ static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
goto __add;
}
}
+
+ if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
+ res->start = -1;
+ res->end = -1;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " irq %d disabled (optional)\n", idx);
+ goto __add;
+ }
+
dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
return -EBUSY;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 48e60171b3ba..e8515ce0d296 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -121,34 +121,46 @@ static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
struct pnp_option *res;
/*
- * Build a functional IRQ-less variant of each MPU option.
+ * Build a functional IRQ-optional variant of each MPU option.
*/
for (res = dev->dependent; res; res = res->next) {
struct pnp_option *curr;
struct pnp_port *port;
- struct pnp_port *copy;
+ struct pnp_port *copy_port;
+ struct pnp_irq *irq;
+ struct pnp_irq *copy_irq;
port = res->port;
- if (!port || !res->irq)
+ irq = res->irq;
+ if (!port || !irq)
continue;
- copy = pnp_alloc(sizeof *copy);
- if (!copy)
+ copy_port = pnp_alloc(sizeof *copy_port);
+ if (!copy_port)
+ break;
+
+ copy_irq = pnp_alloc(sizeof *copy_irq);
+ if (!copy_irq) {
+ kfree(copy_port);
break;
+ }
+
+ *copy_port = *port;
+ copy_port->next = NULL;
- copy->min = port->min;
- copy->max = port->max;
- copy->align = port->align;
- copy->size = port->size;
- copy->flags = port->flags;
+ *copy_irq = *irq;
+ copy_irq->flags |= IORESOURCE_IRQ_OPTIONAL;
+ copy_irq->next = NULL;
curr = pnp_build_option(PNP_RES_PRIORITY_FUNCTIONAL);
if (!curr) {
- kfree(copy);
+ kfree(copy_port);
+ kfree(copy_irq);
break;
}
- curr->port = copy;
+ curr->port = copy_port;
+ curr->irq = copy_irq;
if (prev)
prev->next = curr;
@@ -157,7 +169,7 @@ static struct pnp_option *quirk_isapnp_mpu_options(struct pnp_dev *dev)
prev = curr;
}
if (head)
- dev_info(&dev->dev, "adding IRQ-less MPU options\n");
+ dev_info(&dev->dev, "adding IRQ-optional MPU options\n");
return head;
}
@@ -167,10 +179,6 @@ static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
struct pnp_option *res;
struct pnp_irq *irq;
- /*
- * Distribute the independent IRQ over the dependent options
- */
-
res = dev->independent;
if (!res)
return;
@@ -179,33 +187,8 @@ static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
if (!irq || irq->next)
return;
- res = dev->dependent;
- if (!res)
- return;
-
- while (1) {
- struct pnp_irq *copy;
-
- copy = pnp_alloc(sizeof *copy);
- if (!copy)
- break;
-
- bitmap_copy(copy->map.bits, irq->map.bits, PNP_IRQ_NR);
- copy->flags = irq->flags;
-
- copy->next = res->irq; /* Yes, this is NULL */
- res->irq = copy;
-
- if (!res->next)
- break;
- res = res->next;
- }
- kfree(irq);
-
- res->next = quirk_isapnp_mpu_options(dev);
-
- res = dev->independent;
- res->irq = NULL;
+ irq->flags |= IORESOURCE_IRQ_OPTIONAL;
+ dev_info(&dev->dev, "made independent IRQ optional\n");
}
static void quirk_isapnp_mpu_resources(struct pnp_dev *dev)