2008-01-19 20:00:37

by Thomas Renninger

[permalink] [raw]
Subject: [PATCH] Allocate pnp resources dynamically via krealloc

Allocate pnp resources dynamically via krealloc

The patch is against 2.6.24-rc6-mm1.

Latest BIOS ACPI PNP device resource descriptions may have (especially on the
general device PNP0c02) more than 20 IO port resources.
Reserve the space in a static array wastes a lot of memory on every PNP device
and is not a real option as the number of IO ports could be much greater than
20.

This approach allocates the memory for PNP resources at runtime.
The memory is reallocated in e.g. 8 (for IO port) resource portions.
That means that the previously allocated pointers will get a new address.
Therefore this address must not be stored or re-used as long as krealloc
might still allocate new resources.
First #define pnp_port_ptr(dev,bar) returned the X port pointer of a
pnp_resource_table. I changed it to true/false to not let the idea come up to
store the pointer for later use. The name must still be changed, but I had
no idea for now.

The patch also needs another patch from Rene Herman:
"[PATCH] sound/isa: kill pnp_resource_change."
Sent to the alsa-devel list and it's already included in Takashi's tree
for 2.6.25 inclusion.
This additional patch is only needed for some BIOS workarounds for very old
isa sound cards, so it should not be a problem to have only this one in
someones tree for a while. (This will cause some minor merging conflicts,
though. The rarely used function (pnp_manual_config_dev) return 1 through
this patch and the other one rips it out).


Signed-off-by: Thomas Renninger <[email protected]>

---
drivers/pnp/core.c | 2
drivers/pnp/interface.c | 44 +++-
drivers/pnp/isapnp/core.c | 33 ++-
drivers/pnp/manager.c | 419 +++++++++++++++++++++++++++++++++++------
drivers/pnp/pnpacpi/rsparser.c | 142 ++++++-------
drivers/pnp/pnpbios/rsparser.c | 112 +++++-----
drivers/pnp/resource.c | 16 -
drivers/pnp/support.c | 11 -
drivers/pnp/system.c | 34 +--
include/linux/pnp.h | 59 ++++-
10 files changed, 620 insertions(+), 252 deletions(-)

Index: linux-2.6.24-rc6-mm1/include/linux/pnp.h
===================================================================
--- linux-2.6.24-rc6-mm1.orig/include/linux/pnp.h
+++ linux-2.6.24-rc6-mm1/include/linux/pnp.h
@@ -13,10 +13,6 @@
#include <linux/errno.h>
#include <linux/mod_devicetable.h>

-#define PNP_MAX_PORT 24
-#define PNP_MAX_MEM 12
-#define PNP_MAX_IRQ 2
-#define PNP_MAX_DMA 2
#define PNP_NAME_LEN 50

struct pnp_protocol;
@@ -26,13 +22,26 @@ struct pnp_dev;
* Resource Management
*/

-/* Use these instead of directly reading pnp_dev to get resource information */
+/*
+ * NULL pointer alarm: always check with pnp_port_ptr or pnp_port_valid before
+ * accessing start/end/flags/len values or you might access not allocated mem.
+ * Same for mem, irq and dma macros
+ *
+ * Pointers are not static and they might change, do not store addresses
+ * of resources in the pnp resource table!
+ */
+
+#define pnp_port_ptr(dev,bar) ((dev)->res.allocated_ports > (bar) \
+ ? (1) : (0))
+
#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
#define pnp_port_valid(dev,bar) \
+ (pnp_port_ptr((dev),(bar)) ? \
((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
- == IORESOURCE_IO)
+ == IORESOURCE_IO) : \
+ (0))
#define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \
pnp_port_end((dev),(bar)) == \
@@ -41,12 +50,16 @@ struct pnp_dev;
(pnp_port_end((dev),(bar)) - \
pnp_port_start((dev),(bar)) + 1))

+#define pnp_mem_ptr(dev,bar) ((dev)->res.allocated_mems > (bar) \
+ ? (1) : (0))
#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
#define pnp_mem_valid(dev,bar) \
+ (pnp_mem_ptr((dev),(bar)) ? \
((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
- == IORESOURCE_MEM)
+ == IORESOURCE_MEM) : \
+ (0))
#define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \
pnp_mem_end((dev),(bar)) == \
@@ -55,17 +68,25 @@ struct pnp_dev;
(pnp_mem_end((dev),(bar)) - \
pnp_mem_start((dev),(bar)) + 1))

+#define pnp_irq_ptr(dev,bar) ((dev)->res.allocated_irqs > (bar) \
+ ? (1) : (0))
#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
#define pnp_irq_valid(dev,bar) \
+ (pnp_irq_ptr((dev),(bar)) ? \
((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
- == IORESOURCE_IRQ)
+ == IORESOURCE_IRQ) : \
+ (0))

+#define pnp_dma_ptr(dev,bar) ((dev)->res.allocated_dmas > (bar) \
+ ? (1) : (0))
#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
#define pnp_dma_valid(dev,bar) \
+ (pnp_dma_ptr((dev),(bar)) ? \
((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
- == IORESOURCE_DMA)
+ == IORESOURCE_DMA) : \
+ (0))

#define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1)
@@ -119,10 +140,14 @@ struct pnp_option {
};

struct pnp_resource_table {
- struct resource port_resource[PNP_MAX_PORT];
- struct resource mem_resource[PNP_MAX_MEM];
- struct resource dma_resource[PNP_MAX_DMA];
- struct resource irq_resource[PNP_MAX_IRQ];
+ struct resource *port_resource;
+ unsigned int allocated_ports;
+ struct resource *mem_resource;
+ unsigned int allocated_mems;
+ struct resource *dma_resource;
+ unsigned int allocated_dmas;
+ struct resource *irq_resource;
+ unsigned int allocated_irqs;
};

/*
@@ -365,6 +390,7 @@ int pnp_device_attach(struct pnp_dev *pn
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
extern int pnp_platform_devices;
+extern int pnp_bios_data_parsed;

/* multidevice card support */
int pnp_add_card(struct pnp_card *card);
@@ -399,6 +425,8 @@ int pnp_activate_dev(struct pnp_dev *dev
int pnp_disable_dev(struct pnp_dev *dev);
void pnp_resource_change(struct resource *resource, resource_size_t start,
resource_size_t size);
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res);
+

/* protocol helpers */
int pnp_is_active(struct pnp_dev *dev);
@@ -446,6 +474,7 @@ static inline int pnp_stop_dev(struct pn
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { }
+static inline int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res) { }

/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
@@ -461,9 +490,11 @@ static inline void pnp_unregister_driver
#define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)

#ifdef CONFIG_PNP_DEBUG
-#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
+#define pnp_dbg(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
+void pnp_dump_resources(struct pnp_dev *dev);
#else
#define pnp_dbg(format, arg...) do {} while (0)
+static inline void pnp_dump_resources(struct pnp_dev *dev) { }
#endif

#endif /* __KERNEL__ */
Index: linux-2.6.24-rc6-mm1/drivers/pnp/interface.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/interface.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/interface.c
@@ -267,7 +267,7 @@ static ssize_t pnp_show_current_resource
else
pnp_printf(buffer, "disabled\n");

- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_ptr(dev, i); i++) {
if (pnp_port_valid(dev, i)) {
pnp_printf(buffer, "io");
if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
@@ -280,7 +280,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
+ for (i = 0; pnp_mem_ptr(dev, i); i++) {
if (pnp_mem_valid(dev, i)) {
pnp_printf(buffer, "mem");
if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
@@ -293,7 +293,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_IRQ; i++) {
+ for (i = 0; pnp_irq_ptr(dev, i); i++) {
if (pnp_irq_valid(dev, i)) {
pnp_printf(buffer, "irq");
if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
@@ -303,7 +303,7 @@ static ssize_t pnp_show_current_resource
(unsigned long long)pnp_irq(dev, i));
}
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
+ for (i = 0; pnp_dma_ptr(dev, i); i++) {
if (pnp_dma_valid(dev, i)) {
pnp_printf(buffer, "dma");
if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
@@ -382,6 +382,13 @@ pnp_set_current_resources(struct device
buf += 2;
while (isspace(*buf))
++buf;
+ if (!pnp_port_ptr(dev, nport)) {
+ buf++;
+ pnp_err("Cannot manually set port"
+ "resource %d for device %s",
+ nport, dev->name);
+ continue;
+ }
dev->res.port_resource[nport].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -398,14 +405,19 @@ pnp_set_current_resources(struct device
dev->res.port_resource[nport].flags =
IORESOURCE_IO;
nport++;
- if (nport >= PNP_MAX_PORT)
- break;
continue;
}
if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_port_ptr(dev, nmem)) {
+ buf++;
+ pnp_err("Cannot manually set mem "
+ "resource %d for device %s",
+ nmem, dev->name);
+ continue;
+ }
dev->res.mem_resource[nmem].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -422,36 +434,44 @@ pnp_set_current_resources(struct device
dev->res.mem_resource[nmem].flags =
IORESOURCE_MEM;
nmem++;
- if (nmem >= PNP_MAX_MEM)
- break;
continue;
}
if (!strnicmp(buf, "irq", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_port_ptr(dev, nirq)) {
+ buf++;
+ pnp_err("Cannot manually set irq "
+ "resource %d for device %s",
+ nirq, dev->name);
+ continue;
+ }
dev->res.irq_resource[nirq].start =
dev->res.irq_resource[nirq].end =
simple_strtoul(buf, &buf, 0);
dev->res.irq_resource[nirq].flags =
IORESOURCE_IRQ;
nirq++;
- if (nirq >= PNP_MAX_IRQ)
- break;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_port_ptr(dev, ndma)) {
+ buf++;
+ pnp_err("Cannot manually set dma "
+ "resource %d for device %s",
+ ndma, dev->name);
+ continue;
+ }
dev->res.dma_resource[ndma].start =
dev->res.dma_resource[ndma].end =
simple_strtoul(buf, &buf, 0);
dev->res.dma_resource[ndma].flags =
IORESOURCE_DMA;
ndma++;
- if (ndma >= PNP_MAX_DMA)
- break;
continue;
}
break;
Index: linux-2.6.24-rc6-mm1/drivers/pnp/manager.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/manager.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/manager.c
@@ -15,15 +15,351 @@
#include <linux/mutex.h>
#include "base.h"

+/* Defines the amount of struct resources that will get (re-)alloced
+ * if the resource table runs out of allocated ports/irqs/dma/mems
+ */
+#define PNP_ALLOC_PORT 8
+#define PNP_ALLOC_MEM 4
+#define PNP_ALLOC_IRQ 2
+#define PNP_ALLOC_DMA 2
+
DEFINE_MUTEX(pnp_res_mutex);

+#ifdef CONFIG_PNP_DEBUG
+void pnp_dump_resources(struct pnp_dev *dev)
+{
+ int i;
+ pnp_dbg("Resource table dump:");
+ pnp_dbg("Allocted: ports: %d [%p - %p]",
+ dev->res.allocated_ports, dev->res.port_resource,
+ dev->res.port_resource + (dev->res.allocated_ports *
+ sizeof(struct resource)));
+ for (i = 0; pnp_port_ptr(dev, i); i++) {
+ pnp_dbg("Port %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_port_start(dev, i),
+ (unsigned long)pnp_port_end(dev, i),
+ pnp_port_flags(dev, i));
+ }
+ pnp_dbg("Allocted: mems: %d [%p - %p]",
+ dev->res.allocated_mems, dev->res.mem_resource,
+ dev->res.mem_resource + (dev->res.allocated_mems *
+ sizeof(struct resource)));
+ for (i = 0; pnp_mem_ptr(dev, i); i++) {
+ pnp_dbg("Mem %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_mem_start(dev, i),
+ (unsigned long)pnp_mem_end(dev, i),
+ pnp_mem_flags(dev, i));
+ }
+ pnp_dbg("Allocted: irqs: %d [%p - %p]",
+ dev->res.allocated_irqs, dev->res.irq_resource,
+ dev->res.irq_resource + (dev->res.allocated_irqs *
+ sizeof(struct resource)));
+ for (i = 0; pnp_irq_ptr(dev, i); i++) {
+ pnp_dbg("Irq %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_irq(dev, i),
+ pnp_irq_flags(dev, i));
+ }
+ pnp_dbg("Allocted: dmas: %d [%p - %p]",
+ dev->res.allocated_dmas, dev->res.dma_resource,
+ dev->res.dma_resource + (dev->res.allocated_dmas *
+ sizeof(struct resource)));
+ for (i = 0; pnp_dma_ptr(dev, i); i++) {
+ pnp_dbg("Dma %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_dma(dev, i),
+ pnp_dma_flags(dev, i));
+ }
+}
+#endif
+
+static void pnp_init_io(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_mem(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_irq(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_dma(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+
+/****************************************************************
+ *
+ * pnp_alloc_{port,dma,irq,mem}
+ *
+ * These functions must only be when a device is not active and
+ * can therefore not have any resources requested via kernel/resource.c
+ * If the pnp resource table has not enough (or none) resources of
+ * a specific type allocated, the memory of the array is increased
+ * via krealloc, which results in changed pointers of all already
+ * allocated struct resources in the table.
+ * This would invalidate the addresses passed to request/insert_resource
+ */
+
+static int pnp_alloc_port(struct pnp_resource_table *res)
+{
+ int i;
+
+ if (res->allocated_ports) {
+ /* Resources must not get realloced after device parse time */
+ return -ENOSPC;
+ }
+
+ res->port_resource = krealloc(res->port_resource,
+ (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
+
+ if (!res->port_resource)
+ return -ENOMEM;
+
+ res->allocated_ports += PNP_ALLOC_PORT;
+ for (i = res->allocated_ports - PNP_ALLOC_PORT;
+ i < res->allocated_ports; i++)
+ pnp_init_io(&res->port_resource[i]);
+
+ pnp_dbg("Port allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated ports: %d",
+ res->port_resource,
+ res->port_resource
+ + (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_ports);
+
+ return 0;
+}
+
+static int pnp_alloc_mem(struct pnp_resource_table *res)
+{
+ int i;
+
+ if (res->allocated_mems) {
+ /* Resources must not get realloced after device parse time */
+ return -ENOSPC;
+ }
+ res->mem_resource = krealloc(res->mem_resource,
+ (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM), GFP_KERNEL);
+
+ if (!res->mem_resource)
+ return -ENOMEM;
+
+ res->allocated_mems += PNP_ALLOC_MEM;
+
+ for (i = res->allocated_mems - PNP_ALLOC_MEM; i < res->allocated_mems;
+ i++)
+ pnp_init_mem(&res->mem_resource[i]);
+
+ pnp_dbg("Mem allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated mems: %d",
+ res->mem_resource,
+ res->mem_resource
+ + (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_mems);
+
+ return 0;
+}
+
+static int pnp_alloc_irq(struct pnp_resource_table *res)
+{
+ int i;
+
+ if (res->allocated_irqs) {
+ /* Resources must not get realloced after device parse time */
+ return -ENOSPC;
+ }
+
+ res->irq_resource = krealloc(res->irq_resource,
+ (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ), GFP_KERNEL);
+
+ if (!res->irq_resource)
+ return -ENOMEM;
+
+ res->allocated_irqs += PNP_ALLOC_IRQ;
+ for (i = res->allocated_irqs - PNP_ALLOC_IRQ; i < res->allocated_irqs;
+ i++)
+ pnp_init_irq(&res->irq_resource[i]);
+
+ pnp_dbg("Irq allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated irqs: %d",
+ res->irq_resource,
+ res->irq_resource
+ + (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_irqs);
+ return 0;
+}
+
+static int pnp_alloc_dma(struct pnp_resource_table *res)
+{
+ int i;
+
+ if (res->allocated_dmas) {
+ /* Resources must not get realloced after device parse time */
+ return -ENOSPC;
+ }
+
+ res->dma_resource = krealloc(res->dma_resource,
+ (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA), GFP_KERNEL);
+
+ if (!res->dma_resource)
+ return -ENOMEM;
+
+ res->allocated_dmas += PNP_ALLOC_DMA;
+ for (i = res->allocated_dmas - PNP_ALLOC_DMA; i < res->allocated_dmas;
+ i++)
+ pnp_init_dma(&res->dma_resource[i]);
+
+ pnp_dbg("Dma allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated dmas: %d",
+ res->dma_resource,
+ res->dma_resource
+ + (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_dmas);
+
+ return 0;
+}
+
+#define pnp_print_alloc_err(type, val, x) \
+ pnp_dbg("%s - cannot allocate new resource: %d in func %s " \
+ " - alloc: %d", type, val, __FUNCTION__, x)
+
+
+/*
+ * Assign a resource (IO, MEM, IRQ, DMA) to the resource table.
+ * Searches for an IORESOURCE_UNSET resource entry in the table or reallocs
+ * new resource entries as needed and copies the given resource there.
+ *
+ * returns:
+ * -EFAULT -> if table or res is NULL
+ * -EINVAL -> if the resource has no io, mem, irq or dma flag set
+ * -ENOMEM -> if memory could not get allocated
+ */
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res)
+{
+ int i = 0, ret;
+
+ if (!table || !res)
+ return -EFAULT;
+
+ pnp_dbg("%s", __FUNCTION__);
+
+ if (res->flags & IORESOURCE_IO) {
+ /* find the next unused table entry */
+ while (i < table->allocated_ports) {
+ if (!(table->port_resource[i].flags
+ & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+ /* No unused table entry anymore, allocate new ones */
+ if (table->allocated_ports <= i) {
+ ret = pnp_alloc_port(table);
+ if (ret) {
+ pnp_print_alloc_err("Port", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->port_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_MEM) {
+ while (i < table->allocated_mems) {
+ if (!(table->mem_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_mems <= i) {
+ ret = pnp_alloc_mem(table);
+ if (ret) {
+ pnp_print_alloc_err("System Memory", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->mem_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_IRQ) {
+ while (i < table->allocated_irqs) {
+ if (!(table->irq_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_irqs <= i) {
+ ret = pnp_alloc_irq(table);
+ if (ret) {
+ pnp_print_alloc_err("Irq", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->irq_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_DMA) {
+ while (i < table->allocated_dmas) {
+ if (!(table->dma_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_dmas <= i) {
+ ret = pnp_alloc_dma(table);
+ if (ret) {
+ pnp_print_alloc_err("DMA", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->dma_resource[i], res, sizeof(struct resource));
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+#define pnp_print_assign_err(type, val) \
+ pnp_dbg("%s resource %d not allocated, cannot assign value", \
+ type, val);
+
+
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
resource_size_t *start, *end;
unsigned long *flags;

- if (idx >= PNP_MAX_PORT) {
- dev_err(&dev->dev, "too many I/O port resources\n");
+ if (!pnp_port_ptr(dev, idx)) {
+ pnp_print_assign_err("Port", idx);
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -63,9 +399,8 @@ static int pnp_assign_mem(struct pnp_dev
resource_size_t *start, *end;
unsigned long *flags;

- if (idx >= PNP_MAX_MEM) {
- dev_err(&dev->dev, "too many memory resources\n");
- /* pretend we were successful so at least the manager won't try again */
+ if (!pnp_mem_ptr(dev, idx)) {
+ pnp_print_assign_err("System Memory", idx);
return 1;
}

@@ -120,9 +455,8 @@ static int pnp_assign_irq(struct pnp_dev
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};

- if (idx >= PNP_MAX_IRQ) {
- dev_err(&dev->dev, "too many IRQ resources\n");
- /* pretend we were successful so at least the manager won't try again */
+ if (!pnp_irq_ptr(dev, idx)) {
+ pnp_print_assign_err("Irq", idx);
return 1;
}

@@ -170,8 +504,8 @@ static void pnp_assign_dma(struct pnp_de
1, 3, 5, 6, 7, 0, 2, 4
};

- if (idx >= PNP_MAX_DMA) {
- dev_err(&dev->dev, "too many DMA resources\n");
+ if (!pnp_dma_ptr(dev, idx)) {
+ pnp_print_assign_err("DMA", idx);
return;
}

@@ -208,28 +542,28 @@ void pnp_init_resource_table(struct pnp_
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < table->allocated_irqs; idx++) {
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < table->allocated_dmas; idx++) {
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < table->allocated_ports; idx++) {
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < table->allocated_mems; idx++) {
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0;
@@ -246,7 +580,7 @@ static void pnp_clean_resource_table(str
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < res->allocated_irqs; idx++) {
if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->irq_resource[idx].start = -1;
@@ -254,7 +588,7 @@ static void pnp_clean_resource_table(str
res->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < res->allocated_dmas; idx++) {
if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->dma_resource[idx].start = -1;
@@ -262,7 +596,7 @@ static void pnp_clean_resource_table(str
res->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < res->allocated_ports; idx++) {
if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->port_resource[idx].start = 0;
@@ -270,7 +604,7 @@ static void pnp_clean_resource_table(str
res->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < res->allocated_mems; idx++) {
if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->mem_resource[idx].start = 0;
@@ -295,6 +629,10 @@ static int pnp_assign_resources(struct p
struct pnp_dma *dma;
int nport = 0, nmem = 0, nirq = 0, ndma = 0;

+ /* We must never end up here, this functions are poisson for dynamic
+ allocation via pointer array.
+ */
+ return -1;
if (!pnp_can_configure(dev))
return -ENODEV;

@@ -387,46 +725,11 @@ fail:
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
int mode)
{
- int i;
- struct pnp_resource_table *bak;
-
- if (!pnp_can_configure(dev))
- return -ENODEV;
- bak = pnp_alloc(sizeof(struct pnp_resource_table));
- if (!bak)
- return -ENOMEM;
- *bak = dev->res;
-
- mutex_lock(&pnp_res_mutex);
- dev->res = *res;
- if (!(mode & PNP_CONFIG_FORCE)) {
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_check_port(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_check_mem(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (!pnp_check_irq(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (!pnp_check_dma(dev, i))
- goto fail;
- }
- }
- mutex_unlock(&pnp_res_mutex);
-
- kfree(bak);
- return 0;
-
-fail:
- dev->res = *bak;
- mutex_unlock(&pnp_res_mutex);
- kfree(bak);
- return -EINVAL;
+ /* We must never end up here, these functions are poisson for dynamic
+ allocation via pointer array.
+ */
+ BUG_ON(1);
+ return 1;
}

/**
Index: linux-2.6.24-rc6-mm1/drivers/pnp/pnpacpi/rsparser.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/pnpacpi/rsparser.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/pnpacpi/rsparser.c
@@ -73,21 +73,15 @@ static void pnpacpi_parse_allocated_irqr
u32 gsi, int triggering,
int polarity, int shareable)
{
- int i = 0;
int irq;
int p, t;
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };

if (!valid_IRQ(gsi))
return;

- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
- i++;
- if (i >= PNP_MAX_IRQ) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ "
- "resources: %d \n", PNP_MAX_IRQ);
- return;
- }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
@@ -105,20 +99,26 @@ static void pnpacpi_parse_allocated_irqr
}
}

- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- res->irq_resource[i].flags |= irq_flags(triggering, polarity);
+ new_res.flags |= irq_flags(triggering, polarity);
irq = acpi_register_gsi(gsi, triggering, polarity);
if (irq < 0) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
return;
}

if (shareable)
- res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
+ new_res.flags |= IORESOURCE_IRQ_SHAREABLE;

- res->irq_resource[i].start = irq;
- res->irq_resource[i].end = irq;
+ new_res.start = irq;
+ new_res.end = irq;
pcibios_penalize_isa_irq(irq, 1);
+
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static int dma_flags(int type, int bus_master, int transfer)
@@ -168,75 +168,71 @@ static void pnpacpi_parse_allocated_dmar
u32 dma, int type,
int bus_master, int transfer)
{
- int i = 0;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- res->dma_resource[i].flags |=
- dma_flags(type, bus_master, transfer);
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start = dma;
- res->dma_resource[i].end = dma;
- } else {
- printk(KERN_ERR "pnpacpi: exceeded the max number of DMA "
- "resources: %d \n", PNP_MAX_DMA);
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ new_res.flags |= dma_flags(type, bus_master, transfer);
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = dma;
+ new_res.end = dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
u64 io, u64 len, int io_decode)
{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (io_decode == ACPI_DECODE_16)
- res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = io;
- res->port_resource[i].end = io + len - 1;
- } else {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IO "
- "resources: %d \n", PNP_MAX_PORT);
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (io_decode == ACPI_DECODE_16)
+ new_res.flags |= PNP_PORT_FLAG_16BITADDR;
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = io;
+ new_res.end = io + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
u64 mem, u64 len,
int write_protect)
{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
-
- res->mem_resource[i].start = mem;
- res->mem_resource[i].end = mem + len - 1;
- } else {
- printk(KERN_ERR "pnpacpi: exceeded the max number of mem "
- "resources: %d\n", PNP_MAX_MEM);
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ new_res.flags |= IORESOURCE_MEM_WRITEABLE;
+
+ new_res.start = mem;
+ new_res.end = mem + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
Index: linux-2.6.24-rc6-mm1/drivers/pnp/pnpbios/rsparser.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/pnpbios/rsparser.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/pnpbios/rsparser.c
@@ -56,78 +56,84 @@ inline void pcibios_penalize_isa_irq(int
static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
int irq)
{
- int i = 0;
-
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_IRQ)
- i++;
- if (i < PNP_MAX_IRQ) {
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- if (irq == -1) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->irq_resource[i].start =
- res->irq_resource[i].end = (unsigned long)irq;
- pcibios_penalize_isa_irq(irq, 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };
+
+ if (irq == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)irq;
+ pcibios_penalize_isa_irq(irq, 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
int dma)
{
- int i = 0;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start =
- res->dma_resource[i].end = (unsigned long)dma;
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
int io, int len)
{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = (unsigned long)io;
- res->port_resource[i].end = (unsigned long)(io + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)io;
+ new_res.end = (unsigned long)(io + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
int mem, int len)
{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_MEM)
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->mem_resource[i].start = (unsigned long)mem;
- res->mem_resource[i].end = (unsigned long)(mem + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)mem;
+ new_res.end = (unsigned long)(mem + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
Index: linux-2.6.24-rc6-mm1/drivers/pnp/core.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/core.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/core.c
@@ -129,6 +129,7 @@ int __pnp_add_device(struct pnp_dev *dev
return ret;

pnp_interface_attach_device(dev);
+ pnp_dump_resources(dev);
return 0;
}

@@ -148,6 +149,7 @@ int pnp_add_device(struct pnp_dev *dev)
dev->dev.parent = &dev->protocol->dev;
sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
dev->number);
+ pnp_dbg("Adding device %s - %s", dev->name, dev->dev.bus_id);
ret = __pnp_add_device(dev);
if (ret)
return ret;
Index: linux-2.6.24-rc6-mm1/drivers/pnp/isapnp/core.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/isapnp/core.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/isapnp/core.c
@@ -42,6 +42,7 @@
#include <linux/init.h>
#include <linux/isapnp.h>
#include <linux/mutex.h>
+
#include <asm/io.h>

#if 0
@@ -65,6 +66,12 @@ module_param(isapnp_verbose, int, 0);
MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
MODULE_LICENSE("GPL");

+/* ISAPNP is restricted to these limits by spec */
+#define PNP_MAX_PORT 8
+#define PNP_MAX_MEM 4
+#define PNP_MAX_IRQ 2
+#define PNP_MAX_DMA 2
+
#define _PIDXR 0x279
#define _PNPWRP 0xa79

@@ -942,6 +949,7 @@ static int isapnp_read_resources(struct
struct pnp_resource_table *res)
{
int tmp, ret;
+ struct resource new_res;

dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
@@ -949,16 +957,20 @@ static int isapnp_read_resources(struct
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
- res->port_resource[tmp].start = ret;
- res->port_resource[tmp].flags = IORESOURCE_IO;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_IO;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
ret =
isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
if (!ret)
continue;
- res->mem_resource[tmp].start = ret;
- res->mem_resource[tmp].flags = IORESOURCE_MEM;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_MEM;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
ret =
@@ -966,17 +978,20 @@ static int isapnp_read_resources(struct
8);
if (!ret)
continue;
- res->irq_resource[tmp].start =
- res->irq_resource[tmp].end = ret;
- res->irq_resource[tmp].flags = IORESOURCE_IRQ;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_IRQ;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
res->dma_resource[tmp].start =
- res->dma_resource[tmp].end = ret;
- res->dma_resource[tmp].flags = IORESOURCE_DMA;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_DMA;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
}
return 0;
Index: linux-2.6.24-rc6-mm1/drivers/pnp/resource.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/resource.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/resource.c
@@ -242,7 +242,7 @@ int pnp_check_port(struct pnp_dev *dev,
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_port_ptr(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
@@ -255,7 +255,7 @@ int pnp_check_port(struct pnp_dev *dev,
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
+ for (tmp = 0; pnp_port_ptr(tdev, tmp); tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
if (cannot_compare
(tdev->res.port_resource[tmp].flags))
@@ -300,7 +300,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_mem_ptr(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
@@ -313,7 +313,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
+ for (tmp = 0; pnp_mem_ptr(tdev, tmp); tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
if (cannot_compare
(tdev->res.mem_resource[tmp].flags))
@@ -355,7 +355,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_irq_ptr(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (dev->res.irq_resource[tmp].start == *irq)
return 0;
@@ -388,7 +388,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
+ for (tmp = 0; pnp_irq_ptr(tdev, tmp); tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (cannot_compare
(tdev->res.irq_resource[tmp].flags))
@@ -424,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_dma_ptr(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return 0;
@@ -443,7 +443,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
+ for (tmp = 0; pnp_dma_ptr(tdev, tmp); tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (cannot_compare
(tdev->res.dma_resource[tmp].flags))
Index: linux-2.6.24-rc6-mm1/drivers/pnp/support.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/support.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/support.c
@@ -14,11 +14,16 @@
* resources
* @dev: pointer to the desired PnP device
*/
+
+/* <trenn> This interface is only used by pnpbios and one driver:
+ sound/isa/sscape.c
+ drivers can check for pnp_port_valid... anyway
+ This one is unneeded.
+*/
int pnp_is_active(struct pnp_dev *dev)
{
- if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
- !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
- pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
+ if (dev->res.allocated_ports <= 0 && dev->res.allocated_mems <= 0 &&
+ dev->res.allocated_irqs <= 0 && dev->res.allocated_dmas <= 0)
return 0;
else
return 1;
Index: linux-2.6.24-rc6-mm1/drivers/pnp/system.c
===================================================================
--- linux-2.6.24-rc6-mm1.orig/drivers/pnp/system.c
+++ linux-2.6.24-rc6-mm1/drivers/pnp/system.c
@@ -56,12 +56,9 @@ static struct resource* reserve_range(st
static void reserve_resources_of_dev(struct pnp_dev *dev)
{
int i;
- struct resource **res;
+ struct resource *res;

- res = kzalloc(sizeof(struct resource *) * PNP_MAX_PORT, GFP_KERNEL);
- if (!res)
- return;
- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_ptr(dev, i); i++) {
if (!pnp_port_valid(dev, i))
continue;
if (pnp_port_start(dev, i) == 0)
@@ -79,28 +76,21 @@ static void reserve_resources_of_dev(str
if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
continue; /* invalid */

- res[i] = reserve_range(dev, pnp_port_start(dev, i),
- pnp_port_end(dev, i), 1);
+ res = reserve_range(dev, pnp_port_start(dev, i),
+ pnp_port_end(dev, i), 1);
+ if (res)
+ res->flags &= ~IORESOURCE_BUSY;
}
- for (i = 0; i < PNP_MAX_PORT; i++)
- if (res[i])
- res[i]->flags &= ~IORESOURCE_BUSY;
- kfree(res);
-
- res = kzalloc(sizeof(struct resource *) * PNP_MAX_MEM, GFP_KERNEL);
- if (!res)
- return;
- for (i = 0; i < PNP_MAX_MEM; i++) {
+
+ for (i = 0; i < pnp_mem_ptr(dev, i); i++) {
if (!pnp_mem_valid(dev, i))
continue;

- res[i] = reserve_range(dev, pnp_mem_start(dev, i),
- pnp_mem_end(dev, i), 0);
+ res = reserve_range(dev, pnp_mem_start(dev, i),
+ pnp_mem_end(dev, i), 0);
+ if (res)
+ res->flags &= ~IORESOURCE_BUSY;
}
- for (i = 0; i < PNP_MAX_MEM; i++)
- if (res[i])
- res[i]->flags &= ~IORESOURCE_BUSY;
- kfree(res);
}

static int system_pnp_probe(struct pnp_dev *dev,


2008-01-20 00:23:24

by Pekka Enberg

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc

Hi Thomas,

On Jan 19, 2008 10:00 PM, Thomas Renninger <[email protected]> wrote:
> +static int pnp_alloc_port(struct pnp_resource_table *res)
> +{

[snip]

> + res->port_resource = krealloc(res->port_resource,
> + (sizeof(struct resource) * res->allocated_ports)
> + + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
> +
> + if (!res->port_resource)
> + return -ENOMEM;

When krealloc() returns NULL, there wasn't enough memory to fit the
new size but the original memory region remains unchanged. Therefore
you must not unconditionally overwrite the res->port_resource with the
return value of krealloc(); otherwise you might leak memory.

Pekka

2008-01-20 11:04:39

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc


On Sun, 2008-01-20 at 02:23 +0200, Pekka Enberg wrote:
> Hi Thomas,
>
> On Jan 19, 2008 10:00 PM, Thomas Renninger <[email protected]> wrote:
> > +static int pnp_alloc_port(struct pnp_resource_table *res)
> > +{
>
> [snip]
>
> > + res->port_resource = krealloc(res->port_resource,
> > + (sizeof(struct resource) * res->allocated_ports)
> > + + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
> > +
> > + if (!res->port_resource)
> > + return -ENOMEM;
>
> When krealloc() returns NULL, there wasn't enough memory to fit the
> new size but the original memory region remains unchanged. Therefore
> you must not unconditionally overwrite the res->port_resource with the
> return value of krealloc(); otherwise you might leak memory.
>
Thanks.
While looking at this I found something else..., I think I sent an old
version.

Please hold off, I will double check and resend soon.

Thomas

2008-01-23 17:39:32

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version

On Sun, 2008-01-20 at 02:23 +0200, Pekka Enberg wrote:
> Hi Thomas,
...
> When krealloc() returns NULL, there wasn't enough memory to fit the
> new size but the original memory region remains unchanged.
...

Thanks Pekka, this one should be better now:

The patch is against latest 2.6.24-rc8 not -mm tree:

Allocate pnp resources dynamically via krealloc

Latest BIOS ACPI PNP device resource descriptions may have (especially on the
general device PNP0c02) more than 20 IO port resources.
Reserve the space in a static array wastes a lot of memory on every PNP device
and is not a real option as the number of IO ports could be much greater than
20.

This approach allocates the memory for PNP resources at runtime.
The memory is reallocated in e.g. 8 (for IO port) resource portions.
That means that the previously allocated pointers will get a new address.
Therefore this address must not be stored and/or used as long as krealloc
might still allocate new resources.
>From what I have seen, there is a patch in -mm that gets rid of
registering resources automatically and pass the pointers from
pnp_resource_table to request_region.
While this should still work (only disabled devices where the regions
should have been unregistered should be modifyable) it is potential
dangereous: once you realloc pnp_resource_table pointers you end up
with invalid pointers in the kernel/resource.c implemented list.
Finding this could get difficult as you get really ugly phenomenons with
corrupted memory...


The patch also needs another patch from Rene Herman:
"[PATCH] sound/isa: kill pnp_resource_change."
Sent to the alsa-devel list and it's already included in Takashi's tree
for 2.6.25 inclusion.
The function pnp_resource_change is a nop now and immediately returns to avoid
compile errors. It can be removed as soon as everything is merged together.

This has been tested on rather new machines on i386 and x86_64.
The first with pnpbios also compiled in and forced a test with pnpacpi=off.

isapnp is totally untested. Also the sysfs is rather untested.

I tried to play a bit with the sysfs interface and wanted override
resources without much success:
Unloaded parport_pc driver, then the corresponding pnp device changed state
from active to disabled and now I should have been able to modify BIOS
settings, but it did not work. I expect this is rather unused and could have
been broken before and I did not want to loose more time with it.
Maybe someone else knows more here.


Signed-off-by: Thomas Renninger <[email protected]>

---
drivers/pnp/core.c | 2
drivers/pnp/interface.c | 44 +++-
drivers/pnp/isapnp/core.c | 33 ++-
drivers/pnp/manager.c | 402 +++++++++++++++++++++++++++++++++++------
drivers/pnp/pnpacpi/rsparser.c | 151 +++++++--------
drivers/pnp/pnpbios/rsparser.c | 112 ++++++-----
drivers/pnp/resource.c | 16 -
drivers/pnp/support.c | 11 -
drivers/pnp/system.c | 4
include/linux/pnp.h | 51 +++--
10 files changed, 587 insertions(+), 239 deletions(-)

Index: linux-2.6.23/include/linux/pnp.h
===================================================================
--- linux-2.6.23.orig/include/linux/pnp.h
+++ linux-2.6.23/include/linux/pnp.h
@@ -13,10 +13,6 @@
#include <linux/errno.h>
#include <linux/mod_devicetable.h>

-#define PNP_MAX_PORT 40
-#define PNP_MAX_MEM 12
-#define PNP_MAX_IRQ 2
-#define PNP_MAX_DMA 2
#define PNP_NAME_LEN 50

struct pnp_protocol;
@@ -26,13 +22,24 @@ struct pnp_dev;
* Resource Management
*/

-/* Use these instead of directly reading pnp_dev to get resource information */
+/*
+ * NULL pointer alarm: always check with pnp_port_ok or pnp_port_valid before
+ * accessing start/end/flags/len values or you might access not allocated mem.
+ * Same for mem, irq and dma macros
+ *
+ * Pointers are not static and they might change, do not store addresses
+ * of resources in the pnp resource table!
+ */
+
+#define pnp_port_ok(dev,bar) ((dev)->res.allocated_ports > (bar))
+
#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
#define pnp_port_valid(dev,bar) \
+ (pnp_port_ok((dev),(bar)) && \
((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
- == IORESOURCE_IO)
+ == IORESOURCE_IO))
#define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \
pnp_port_end((dev),(bar)) == \
@@ -41,12 +48,14 @@ struct pnp_dev;
(pnp_port_end((dev),(bar)) - \
pnp_port_start((dev),(bar)) + 1))

+#define pnp_mem_ok(dev,bar) ((dev)->res.allocated_mems > (bar))
#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
#define pnp_mem_valid(dev,bar) \
+ (pnp_mem_ok((dev),(bar)) && \
((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
- == IORESOURCE_MEM)
+ == IORESOURCE_MEM))
#define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \
pnp_mem_end((dev),(bar)) == \
@@ -55,17 +64,21 @@ struct pnp_dev;
(pnp_mem_end((dev),(bar)) - \
pnp_mem_start((dev),(bar)) + 1))

+#define pnp_irq_ok(dev,bar) ((dev)->res.allocated_irqs > (bar))
#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
#define pnp_irq_valid(dev,bar) \
+ (pnp_irq_ok((dev),(bar)) && \
((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
- == IORESOURCE_IRQ)
+ == IORESOURCE_IRQ))

+#define pnp_dma_ok(dev,bar) ((dev)->res.allocated_dmas > (bar))
#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
#define pnp_dma_valid(dev,bar) \
+ (pnp_dma_ok((dev),(bar)) && \
((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
- == IORESOURCE_DMA)
+ == IORESOURCE_DMA))

#define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1)
@@ -119,10 +132,14 @@ struct pnp_option {
};

struct pnp_resource_table {
- struct resource port_resource[PNP_MAX_PORT];
- struct resource mem_resource[PNP_MAX_MEM];
- struct resource dma_resource[PNP_MAX_DMA];
- struct resource irq_resource[PNP_MAX_IRQ];
+ struct resource *port_resource;
+ unsigned int allocated_ports;
+ struct resource *mem_resource;
+ unsigned int allocated_mems;
+ struct resource *dma_resource;
+ unsigned int allocated_dmas;
+ struct resource *irq_resource;
+ unsigned int allocated_irqs;
};

/*
@@ -364,6 +381,7 @@ int pnp_device_attach(struct pnp_dev *pn
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
extern int pnp_platform_devices;
+extern int pnp_bios_data_parsed;

/* multidevice card support */
int pnp_add_card(struct pnp_card *card);
@@ -398,6 +416,8 @@ int pnp_activate_dev(struct pnp_dev *dev
int pnp_disable_dev(struct pnp_dev *dev);
void pnp_resource_change(struct resource *resource, resource_size_t start,
resource_size_t size);
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res);
+

/* protocol helpers */
int pnp_is_active(struct pnp_dev *dev);
@@ -445,6 +465,7 @@ static inline int pnp_stop_dev(struct pn
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { }
+static inline int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res) { }

/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
@@ -460,9 +481,11 @@ static inline void pnp_unregister_driver
#define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)

#ifdef CONFIG_PNP_DEBUG
-#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
+#define pnp_dbg(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
+void pnp_dump_resources(struct pnp_dev *dev);
#else
#define pnp_dbg(format, arg...) do {} while (0)
+static inline void pnp_dump_resources(struct pnp_dev *dev) { }
#endif

#endif /* __KERNEL__ */
Index: linux-2.6.23/drivers/pnp/interface.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/interface.c
+++ linux-2.6.23/drivers/pnp/interface.c
@@ -264,7 +264,7 @@ static ssize_t pnp_show_current_resource
else
pnp_printf(buffer, "disabled\n");

- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_ok(dev, i); i++) {
if (pnp_port_valid(dev, i)) {
pnp_printf(buffer, "io");
if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
@@ -277,7 +277,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
+ for (i = 0; pnp_mem_ok(dev, i); i++) {
if (pnp_mem_valid(dev, i)) {
pnp_printf(buffer, "mem");
if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
@@ -290,7 +290,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_IRQ; i++) {
+ for (i = 0; pnp_irq_ok(dev, i); i++) {
if (pnp_irq_valid(dev, i)) {
pnp_printf(buffer, "irq");
if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
@@ -300,7 +300,7 @@ static ssize_t pnp_show_current_resource
(unsigned long long)pnp_irq(dev, i));
}
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
+ for (i = 0; pnp_dma_ok(dev, i); i++) {
if (pnp_dma_valid(dev, i)) {
pnp_printf(buffer, "dma");
if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
@@ -381,6 +381,13 @@ pnp_set_current_resources(struct device
buf += 2;
while (isspace(*buf))
++buf;
+ if (!pnp_port_ok(dev, nport)) {
+ buf++;
+ pnp_err("Cannot manually set port"
+ "resource %d for device %s",
+ nport, dev->name);
+ continue;
+ }
dev->res.port_resource[nport].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -397,14 +404,19 @@ pnp_set_current_resources(struct device
dev->res.port_resource[nport].flags =
IORESOURCE_IO;
nport++;
- if (nport >= PNP_MAX_PORT)
- break;
continue;
}
if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_mem_ok(dev, nmem)) {
+ buf++;
+ pnp_err("Cannot manually set mem "
+ "resource %d for device %s",
+ nmem, dev->name);
+ continue;
+ }
dev->res.mem_resource[nmem].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -421,36 +433,44 @@ pnp_set_current_resources(struct device
dev->res.mem_resource[nmem].flags =
IORESOURCE_MEM;
nmem++;
- if (nmem >= PNP_MAX_MEM)
- break;
continue;
}
if (!strnicmp(buf, "irq", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_irq_ok(dev, nirq)) {
+ buf++;
+ pnp_err("Cannot manually set irq "
+ "resource %d for device %s",
+ nirq, dev->name);
+ continue;
+ }
dev->res.irq_resource[nirq].start =
dev->res.irq_resource[nirq].end =
simple_strtoul(buf, &buf, 0);
dev->res.irq_resource[nirq].flags =
IORESOURCE_IRQ;
nirq++;
- if (nirq >= PNP_MAX_IRQ)
- break;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_dma_ok(dev, ndma)) {
+ buf++;
+ pnp_err("Cannot manually set dma "
+ "resource %d for device %s",
+ ndma, dev->name);
+ continue;
+ }
dev->res.dma_resource[ndma].start =
dev->res.dma_resource[ndma].end =
simple_strtoul(buf, &buf, 0);
dev->res.dma_resource[ndma].flags =
IORESOURCE_DMA;
ndma++;
- if (ndma >= PNP_MAX_DMA)
- break;
continue;
}
break;
Index: linux-2.6.23/drivers/pnp/manager.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/manager.c
+++ linux-2.6.23/drivers/pnp/manager.c
@@ -14,15 +14,338 @@
#include <linux/bitmap.h>
#include "base.h"

+/* Defines the amount of struct resources that will get (re-)alloced
+ * if the resource table runs out of allocated ports/irqs/dma/mems
+ */
+#define PNP_ALLOC_PORT 8
+#define PNP_ALLOC_MEM 4
+#define PNP_ALLOC_IRQ 2
+#define PNP_ALLOC_DMA 2
+
DECLARE_MUTEX(pnp_res_mutex);

+#ifdef CONFIG_PNP_DEBUG
+void pnp_dump_resources(struct pnp_dev *dev)
+{
+ int i;
+ pnp_dbg("Resource table dump:");
+ pnp_dbg("Allocted: ports: %d [%p - %p]",
+ dev->res.allocated_ports, dev->res.port_resource,
+ dev->res.port_resource + (dev->res.allocated_ports *
+ sizeof(struct resource)));
+ for (i = 0; pnp_port_ok(dev, i); i++) {
+ pnp_dbg("Port %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_port_start(dev, i),
+ (unsigned long)pnp_port_end(dev, i),
+ pnp_port_flags(dev, i));
+ }
+ pnp_dbg("Allocted: mems: %d [%p - %p]",
+ dev->res.allocated_mems, dev->res.mem_resource,
+ dev->res.mem_resource + (dev->res.allocated_mems *
+ sizeof(struct resource)));
+ for (i = 0; pnp_mem_ok(dev, i); i++) {
+ pnp_dbg("Mem %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_mem_start(dev, i),
+ (unsigned long)pnp_mem_end(dev, i),
+ pnp_mem_flags(dev, i));
+ }
+ pnp_dbg("Allocted: irqs: %d [%p - %p]",
+ dev->res.allocated_irqs, dev->res.irq_resource,
+ dev->res.irq_resource + (dev->res.allocated_irqs *
+ sizeof(struct resource)));
+ for (i = 0; pnp_irq_ok(dev, i); i++) {
+ pnp_dbg("Irq %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_irq(dev, i),
+ pnp_irq_flags(dev, i));
+ }
+ pnp_dbg("Allocted: dmas: %d [%p - %p]",
+ dev->res.allocated_dmas, dev->res.dma_resource,
+ dev->res.dma_resource + (dev->res.allocated_dmas *
+ sizeof(struct resource)));
+ for (i = 0; pnp_dma_ok(dev, i); i++) {
+ pnp_dbg("Dma %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_dma(dev, i),
+ pnp_dma_flags(dev, i));
+ }
+}
+#endif
+
+static void pnp_init_io(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_mem(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_irq(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_dma(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+
+/****************************************************************
+ *
+ * pnp_alloc_{port,dma,irq,mem}
+ *
+ * These functions must only be when a device is not active and
+ * can therefore not have any resources requested via kernel/resource.c
+ * If the pnp resource table has not enough (or none) resources of
+ * a specific type allocated, the memory of the array is increased
+ * via krealloc, which results in changed pointers of all already
+ * allocated struct resources in the table.
+ * This would invalidate the addresses passed to request/insert_resource
+ */
+
+static int pnp_alloc_port(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->port_resource,
+ (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->port_resource = ret;
+
+ res->allocated_ports += PNP_ALLOC_PORT;
+ for (i = res->allocated_ports - PNP_ALLOC_PORT;
+ i < res->allocated_ports; i++)
+ pnp_init_io(&res->port_resource[i]);
+
+ pnp_dbg("Port allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated ports: %d",
+ res->port_resource,
+ res->port_resource
+ + (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_ports);
+
+ return 0;
+}
+
+static int pnp_alloc_mem(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->mem_resource,
+ (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->mem_resource = ret;
+
+ res->allocated_mems += PNP_ALLOC_MEM;
+
+ for (i = res->allocated_mems - PNP_ALLOC_MEM; i < res->allocated_mems;
+ i++)
+ pnp_init_mem(&res->mem_resource[i]);
+
+ pnp_dbg("Mem allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated mems: %d",
+ res->mem_resource,
+ res->mem_resource
+ + (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_mems);
+
+ return 0;
+}
+
+static int pnp_alloc_irq(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->irq_resource,
+ (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->irq_resource = ret;
+
+ res->allocated_irqs += PNP_ALLOC_IRQ;
+ for (i = res->allocated_irqs - PNP_ALLOC_IRQ; i < res->allocated_irqs;
+ i++)
+ pnp_init_irq(&res->irq_resource[i]);
+
+ pnp_dbg("Irq allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated irqs: %d",
+ res->irq_resource,
+ res->irq_resource
+ + (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_irqs);
+ return 0;
+}
+
+static int pnp_alloc_dma(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->dma_resource,
+ (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->dma_resource = ret;
+
+ res->allocated_dmas += PNP_ALLOC_DMA;
+ for (i = res->allocated_dmas - PNP_ALLOC_DMA; i < res->allocated_dmas;
+ i++)
+ pnp_init_dma(&res->dma_resource[i]);
+
+ pnp_dbg("Dma allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated dmas: %d",
+ res->dma_resource,
+ res->dma_resource
+ + (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_dmas);
+
+ return 0;
+}
+
+#define pnp_print_alloc_err(type, val, x) \
+ pnp_dbg("%s - cannot allocate new resource: %d in func %s " \
+ " - alloc: %d", type, val, __FUNCTION__, x)
+
+
+/*
+ * Assign a resource (IO, MEM, IRQ, DMA) to the resource table.
+ * Searches for an IORESOURCE_UNSET resource entry in the table or reallocs
+ * new resource entries as needed and copies the given resource there.
+ */
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res)
+{
+ int i = 0, ret;
+
+ if (!table || !res)
+ return -EINVAL;
+
+ if (res->flags & IORESOURCE_IO) {
+ /* find the next unused table entry */
+ while (i < table->allocated_ports) {
+ if (!(table->port_resource[i].flags
+ & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+ /* No unused table entry anymore, allocate new ones */
+ if (table->allocated_ports <= i) {
+ ret = pnp_alloc_port(table);
+ if (ret) {
+ pnp_print_alloc_err("Port", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->port_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_MEM) {
+ while (i < table->allocated_mems) {
+ if (!(table->mem_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_mems <= i) {
+ ret = pnp_alloc_mem(table);
+ if (ret) {
+ pnp_print_alloc_err("System Memory", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->mem_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_IRQ) {
+ while (i < table->allocated_irqs) {
+ if (!(table->irq_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_irqs <= i) {
+ ret = pnp_alloc_irq(table);
+ if (ret) {
+ pnp_print_alloc_err("Irq", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->irq_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_DMA) {
+ while (i < table->allocated_dmas) {
+ if (!(table->dma_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_dmas <= i) {
+ ret = pnp_alloc_dma(table);
+ if (ret) {
+ pnp_print_alloc_err("DMA", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->dma_resource[i], res, sizeof(struct resource));
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+#define pnp_print_assign_err(type, val) \
+ pnp_dbg("%s resource %d not allocated, cannot assign value", \
+ type, val);
+
+
+
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
resource_size_t *start, *end;
unsigned long *flags;

- if (idx >= PNP_MAX_PORT) {
- dev_err(&dev->dev, "too many I/O port resources\n");
+ if (!pnp_port_ok(dev, idx)) {
+ pnp_print_assign_err("Port", idx);
/* pretend we were successful so at least the manager won't try again */
return 1;
}
@@ -62,9 +385,8 @@ static int pnp_assign_mem(struct pnp_dev
resource_size_t *start, *end;
unsigned long *flags;

- if (idx >= PNP_MAX_MEM) {
- dev_err(&dev->dev, "too many memory resources\n");
- /* pretend we were successful so at least the manager won't try again */
+ if (!pnp_mem_ok(dev, idx)) {
+ pnp_print_assign_err("System Memory", idx);
return 1;
}

@@ -119,9 +441,8 @@ static int pnp_assign_irq(struct pnp_dev
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};

- if (idx >= PNP_MAX_IRQ) {
- dev_err(&dev->dev, "too many IRQ resources\n");
- /* pretend we were successful so at least the manager won't try again */
+ if (!pnp_irq_ok(dev, idx)) {
+ pnp_print_assign_err("Irq", idx);
return 1;
}

@@ -169,8 +490,8 @@ static void pnp_assign_dma(struct pnp_de
1, 3, 5, 6, 7, 0, 2, 4
};

- if (idx >= PNP_MAX_DMA) {
- dev_err(&dev->dev, "too many DMA resources\n");
+ if (!pnp_dma_ok(dev, idx)) {
+ pnp_print_assign_err("DMA", idx);
return;
}

@@ -207,28 +528,28 @@ void pnp_init_resource_table(struct pnp_
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < table->allocated_irqs; idx++) {
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < table->allocated_dmas; idx++) {
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < table->allocated_ports; idx++) {
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < table->allocated_mems; idx++) {
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0;
@@ -245,7 +566,7 @@ static void pnp_clean_resource_table(str
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < res->allocated_irqs; idx++) {
if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->irq_resource[idx].start = -1;
@@ -253,7 +574,7 @@ static void pnp_clean_resource_table(str
res->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < res->allocated_dmas; idx++) {
if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->dma_resource[idx].start = -1;
@@ -261,7 +582,7 @@ static void pnp_clean_resource_table(str
res->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < res->allocated_ports; idx++) {
if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->port_resource[idx].start = 0;
@@ -269,7 +590,7 @@ static void pnp_clean_resource_table(str
res->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < res->allocated_mems; idx++) {
if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->mem_resource[idx].start = 0;
@@ -386,46 +707,12 @@ fail:
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
int mode)
{
- int i;
- struct pnp_resource_table *bak;
-
- if (!pnp_can_configure(dev))
- return -ENODEV;
- bak = pnp_alloc(sizeof(struct pnp_resource_table));
- if (!bak)
- return -ENOMEM;
- *bak = dev->res;
-
- down(&pnp_res_mutex);
- dev->res = *res;
- if (!(mode & PNP_CONFIG_FORCE)) {
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_check_port(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_check_mem(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (!pnp_check_irq(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (!pnp_check_dma(dev, i))
- goto fail;
- }
- }
- up(&pnp_res_mutex);
-
- kfree(bak);
- return 0;
+ /* We must never end up here, these functions are poisson for dynamic
+ allocation via pointer array.
+ */
+ BUG_ON(1);
+ return 1;

-fail:
- dev->res = *bak;
- up(&pnp_res_mutex);
- kfree(bak);
- return -EINVAL;
}

/**
@@ -563,6 +850,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
void pnp_resource_change(struct resource *resource, resource_size_t start,
resource_size_t size)
{
+ return;
resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
resource->start = start;
resource->end = start + size - 1;
Index: linux-2.6.23/drivers/pnp/pnpacpi/rsparser.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/pnpacpi/rsparser.c
+++ linux-2.6.23/drivers/pnp/pnpacpi/rsparser.c
@@ -73,23 +73,16 @@ static void pnpacpi_parse_allocated_irqr
u32 gsi, int triggering,
int polarity, int shareable)
{
- int i = 0;
int irq;
int p, t;
- static unsigned char warned;
+
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };

if (!valid_IRQ(gsi))
return;

- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
- i++;
- if (i >= PNP_MAX_IRQ && !warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ "
- "resources: %d \n", PNP_MAX_IRQ);
- warned = 1;
- return;
- }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
@@ -107,20 +100,26 @@ static void pnpacpi_parse_allocated_irqr
}
}

- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- res->irq_resource[i].flags |= irq_flags(triggering, polarity);
+ new_res.flags |= irq_flags(triggering, polarity);
irq = acpi_register_gsi(gsi, triggering, polarity);
if (irq < 0) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
return;
}

if (shareable)
- res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
+ new_res.flags |= IORESOURCE_IRQ_SHAREABLE;

- res->irq_resource[i].start = irq;
- res->irq_resource[i].end = irq;
+ new_res.start = irq;
+ new_res.end = irq;
pcibios_penalize_isa_irq(irq, 1);
+
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static int dma_flags(int type, int bus_master, int transfer)
@@ -170,81 +169,71 @@ static void pnpacpi_parse_allocated_dmar
u32 dma, int type,
int bus_master, int transfer)
{
- int i = 0;
- static unsigned char warned;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- res->dma_resource[i].flags |=
- dma_flags(type, bus_master, transfer);
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start = dma;
- res->dma_resource[i].end = dma;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of DMA "
- "resources: %d \n", PNP_MAX_DMA);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ new_res.flags |= dma_flags(type, bus_master, transfer);
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = dma;
+ new_res.end = dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
u64 io, u64 len, int io_decode)
{
- int i = 0;
- static unsigned char warned;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (io_decode == ACPI_DECODE_16)
- res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = io;
- res->port_resource[i].end = io + len - 1;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IO "
- "resources: %d \n", PNP_MAX_PORT);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (io_decode == ACPI_DECODE_16)
+ new_res.flags |= PNP_PORT_FLAG_16BITADDR;
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = io;
+ new_res.end = io + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
u64 mem, u64 len,
int write_protect)
{
- int i = 0;
- static unsigned char warned;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
-
- res->mem_resource[i].start = mem;
- res->mem_resource[i].end = mem + len - 1;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of mem "
- "resources: %d\n", PNP_MAX_MEM);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ new_res.flags |= IORESOURCE_MEM_WRITEABLE;
+
+ new_res.start = mem;
+ new_res.end = mem + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
Index: linux-2.6.23/drivers/pnp/pnpbios/rsparser.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/pnpbios/rsparser.c
+++ linux-2.6.23/drivers/pnp/pnpbios/rsparser.c
@@ -56,78 +56,84 @@ inline void pcibios_penalize_isa_irq(int
static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
int irq)
{
- int i = 0;
-
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_IRQ)
- i++;
- if (i < PNP_MAX_IRQ) {
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- if (irq == -1) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->irq_resource[i].start =
- res->irq_resource[i].end = (unsigned long)irq;
- pcibios_penalize_isa_irq(irq, 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };
+
+ if (irq == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)irq;
+ pcibios_penalize_isa_irq(irq, 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
int dma)
{
- int i = 0;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start =
- res->dma_resource[i].end = (unsigned long)dma;
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
int io, int len)
{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = (unsigned long)io;
- res->port_resource[i].end = (unsigned long)(io + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)io;
+ new_res.end = (unsigned long)(io + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
int mem, int len)
{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_MEM)
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->mem_resource[i].start = (unsigned long)mem;
- res->mem_resource[i].end = (unsigned long)(mem + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)mem;
+ new_res.end = (unsigned long)(mem + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
Index: linux-2.6.23/drivers/pnp/core.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/core.c
+++ linux-2.6.23/drivers/pnp/core.c
@@ -129,6 +129,7 @@ int __pnp_add_device(struct pnp_dev *dev
return ret;

pnp_interface_attach_device(dev);
+ pnp_dump_resources(dev);
return 0;
}

@@ -148,6 +149,7 @@ int pnp_add_device(struct pnp_dev *dev)
dev->dev.parent = &dev->protocol->dev;
sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
dev->number);
+ pnp_dbg("Adding device %s - %s", dev->name, dev->dev.bus_id);
ret = __pnp_add_device(dev);
if (ret)
return ret;
Index: linux-2.6.23/drivers/pnp/isapnp/core.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/isapnp/core.c
+++ linux-2.6.23/drivers/pnp/isapnp/core.c
@@ -42,6 +42,7 @@
#include <linux/init.h>
#include <linux/isapnp.h>
#include <linux/mutex.h>
+
#include <asm/io.h>

#if 0
@@ -65,6 +66,12 @@ module_param(isapnp_verbose, int, 0);
MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
MODULE_LICENSE("GPL");

+/* ISAPNP is restricted to these limits by spec */
+#define PNP_MAX_PORT 8
+#define PNP_MAX_MEM 4
+#define PNP_MAX_IRQ 2
+#define PNP_MAX_DMA 2
+
#define _PIDXR 0x279
#define _PNPWRP 0xa79

@@ -942,6 +949,7 @@ static int isapnp_read_resources(struct
struct pnp_resource_table *res)
{
int tmp, ret;
+ struct resource new_res;

dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
@@ -949,16 +957,20 @@ static int isapnp_read_resources(struct
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
- res->port_resource[tmp].start = ret;
- res->port_resource[tmp].flags = IORESOURCE_IO;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_IO;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
ret =
isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
if (!ret)
continue;
- res->mem_resource[tmp].start = ret;
- res->mem_resource[tmp].flags = IORESOURCE_MEM;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_MEM;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
ret =
@@ -966,17 +978,20 @@ static int isapnp_read_resources(struct
8);
if (!ret)
continue;
- res->irq_resource[tmp].start =
- res->irq_resource[tmp].end = ret;
- res->irq_resource[tmp].flags = IORESOURCE_IRQ;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_IRQ;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
res->dma_resource[tmp].start =
- res->dma_resource[tmp].end = ret;
- res->dma_resource[tmp].flags = IORESOURCE_DMA;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_DMA;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}
}
return 0;
Index: linux-2.6.23/drivers/pnp/resource.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/resource.c
+++ linux-2.6.23/drivers/pnp/resource.c
@@ -242,7 +242,7 @@ int pnp_check_port(struct pnp_dev *dev,
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_port_ok(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
@@ -255,7 +255,7 @@ int pnp_check_port(struct pnp_dev *dev,
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
+ for (tmp = 0; pnp_port_ok(tdev, tmp); tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
if (cannot_compare
(tdev->res.port_resource[tmp].flags))
@@ -300,7 +300,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_mem_ok(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
@@ -313,7 +313,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
+ for (tmp = 0; pnp_mem_ok(tdev, tmp); tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
if (cannot_compare
(tdev->res.mem_resource[tmp].flags))
@@ -355,7 +355,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_irq_ok(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (dev->res.irq_resource[tmp].start == *irq)
return 0;
@@ -388,7 +388,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
+ for (tmp = 0; pnp_irq_ok(tdev, tmp); tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (cannot_compare
(tdev->res.irq_resource[tmp].flags))
@@ -424,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_dma_ok(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return 0;
@@ -443,7 +443,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
+ for (tmp = 0; pnp_dma_ok(tdev, tmp); tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (cannot_compare
(tdev->res.dma_resource[tmp].flags))
Index: linux-2.6.23/drivers/pnp/support.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/support.c
+++ linux-2.6.23/drivers/pnp/support.c
@@ -14,11 +14,16 @@
* resources
* @dev: pointer to the desired PnP device
*/
+
+/* <trenn> This interface is only used by pnpbios and one driver:
+ sound/isa/sscape.c
+ drivers can check for pnp_port_valid... anyway
+ This one is not needed.
+*/
int pnp_is_active(struct pnp_dev *dev)
{
- if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
- !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
- pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
+ if (dev->res.allocated_ports <= 0 && dev->res.allocated_mems <= 0 &&
+ dev->res.allocated_irqs <= 0 && dev->res.allocated_dmas <= 0)
return 0;
else
return 1;
Index: linux-2.6.23/drivers/pnp/system.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/system.c
+++ linux-2.6.23/drivers/pnp/system.c
@@ -58,7 +58,7 @@ static void reserve_resources_of_dev(str
{
int i;

- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_ok(dev, i); i++) {
if (!pnp_port_valid(dev, i))
continue;
if (pnp_port_start(dev, i) == 0)
@@ -80,7 +80,7 @@ static void reserve_resources_of_dev(str
pnp_port_end(dev, i), 1);
}

- for (i = 0; i < PNP_MAX_MEM; i++) {
+ for (i = 0; pnp_mem_ok(dev, i); i++) {
if (!pnp_mem_valid(dev, i))
continue;


2008-01-27 19:19:24

by Rene Herman

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version

On 23-01-08 18:38, Thomas Renninger wrote:

> isapnp is totally untested. Also the sysfs is rather untested.

If nobody beats me to it I'll debug this myself later on, but as a quick
heads up:

pnp: the driver 'cs4236_isapnp' has been registered
cs4236_isapnp 01:01.00: driver attached
cs4236_isapnp 01:01.02: driver attached
cs4236_isapnp 01:01.03: driver attached
pnp: Port resource 0 not allocated, cannot assign value
pnp: Port resource 1 not allocated, cannot assign value
pnp: Port resource 2 not allocated, cannot assign value
pnp: Irq resource 0 not allocated, cannot assign value
pnp: DMA resource 0 not allocated, cannot assign value
pnp: DMA resource 1 not allocated, cannot assign value
BUG: unable to handle kernel NULL pointer dereference at virtual address
0000000c
printing eip: c10e76d9 *pde = 00000000
Oops: 0000 [#1] PREEMPT
Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
snd_page_alloc snd soundcore nfsd lockd nfs_acl sunrpc exportfs

Pid: 1353, comm: modprobe Not tainted (2.6.24-local #2)
EIP: 0060:[<c10e76d9>] EFLAGS: 00010246 CPU: 0
EIP is at isapnp_set_resources+0x4d/0x132
EAX: 00000000 EBX: 00000000 ECX: e3c8f000 EDX: 00000000
ESI: 00000000 EDI: ef8f5964 EBP: ef8f5800 ESP: e3c8fe5c
DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
Process modprobe (pid: 1353, ti=e3c8f000 task=ed2c2f90 task.ti=e3c8f000)
Stack: ef8f5800 ef8f5888 f0a4e0a4 ed349000 c10e48c8 c10e373a f0a4e0c0 ef8f5800
ef8f5800 00000000 c10e5101 ef8f5800 f0a4b559 00000286 00000001 f0a4d780
c10e330d c12b7c6c ef8f5e00 ed37f140 ed3491bc ef8f5e00 ed37f140 f0a4e0a4
Call Trace:
[<c10e48c8>] pnp_start_dev+0x55/0x9e
[<c10e373a>] pnp_request_card_device+0x9b/0xbe
[<c10e5101>] pnp_activate_dev+0x23/0x39
[<f0a4b559>] snd_cs423x_pnpc_detect+0xe4/0x35f [snd_cs4236]
[<c10e330d>] pnp_alloc+0xe/0x25
[<c10e3652>] card_probe+0xba/0x107
[<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
[<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
[<c103258a>] sys_init_module+0x1379/0x149b
[<c104773a>] unmap_region+0xe5/0x100
[<c1003d62>] syscall_call+0x7/0xb
=======================
Code: ff ff ff c7 85 54 01 00 00 01 00 00 00 eb 18 0f b7 12 8d 44 1b 60 43
83 c6 1c 0f b6 c0 e8 ce fd ff ff 83 fb 08 74 13 89 f2 03 17 <8b> 42 0c 25 00
01 00 20 3d 00 01 00 00 74 d5 31 db 31 f6 eb 25
EIP: [<c10e76d9>] isapnp_set_resources+0x4d/0x132 SS:ESP 0068:e3c8fe5c
---[ end trace f836fd70d1d20199 ]---

Rene.

2008-01-27 21:03:18

by Pekka Enberg

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version

Hi Thomas,

On Sun, 2008-01-20 at 02:23 +0200, Pekka Enberg wrote:
> > When krealloc() returns NULL, there wasn't enough memory to fit the
> > new size but the original memory region remains unchanged.

On Jan 23, 2008 7:38 PM, Thomas Renninger <[email protected]> wrote:
> Thanks Pekka, this one should be better now:

Yeah, the krealloc() bits look good me. Thanks!

Pekka

2008-01-28 14:21:54

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version

On Sun, 2008-01-27 at 20:19 +0100, Rene Herman wrote:
> On 23-01-08 18:38, Thomas Renninger wrote:
>
> > isapnp is totally untested. Also the sysfs is rather untested.
>
> If nobody beats me to it I'll debug this myself later on, but as a quick
> heads up:
I think I know what is going on.
While pnpbios and pnpacpi theoretically do not have limits, isapnp has
spec restrictions (AFAIK, I have not read this up, but taken over from
previous implementation...).
Therefore in isapnp I wanted to stay with:
#define PNP_MAX_PORT 8
#define PNP_MAX_MEM 4
#define PNP_MAX_IRQ 2
#define PNP_MAX_DMA 2
but I have forgotten to malloc one portion for each at init time, or
even better one portion as soon as one is needed.
As said, isapnp is more or less untested, thanks a lot for trying out.
I will send an updated version soon.

Thanks,

Thomas

> pnp: the driver 'cs4236_isapnp' has been registered
> cs4236_isapnp 01:01.00: driver attached
> cs4236_isapnp 01:01.02: driver attached
> cs4236_isapnp 01:01.03: driver attached
> pnp: Port resource 0 not allocated, cannot assign value
> pnp: Port resource 1 not allocated, cannot assign value
> pnp: Port resource 2 not allocated, cannot assign value
> pnp: Irq resource 0 not allocated, cannot assign value
> pnp: DMA resource 0 not allocated, cannot assign value
> pnp: DMA resource 1 not allocated, cannot assign value
> BUG: unable to handle kernel NULL pointer dereference at virtual address
> 0000000c
> printing eip: c10e76d9 *pde = 00000000
> Oops: 0000 [#1] PREEMPT
> Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
> snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
> snd_page_alloc snd soundcore nfsd lockd nfs_acl sunrpc exportfs
>
> Pid: 1353, comm: modprobe Not tainted (2.6.24-local #2)
> EIP: 0060:[<c10e76d9>] EFLAGS: 00010246 CPU: 0
> EIP is at isapnp_set_resources+0x4d/0x132
> EAX: 00000000 EBX: 00000000 ECX: e3c8f000 EDX: 00000000
> ESI: 00000000 EDI: ef8f5964 EBP: ef8f5800 ESP: e3c8fe5c
> DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
> Process modprobe (pid: 1353, ti=e3c8f000 task=ed2c2f90 task.ti=e3c8f000)
> Stack: ef8f5800 ef8f5888 f0a4e0a4 ed349000 c10e48c8 c10e373a f0a4e0c0 ef8f5800
> ef8f5800 00000000 c10e5101 ef8f5800 f0a4b559 00000286 00000001 f0a4d780
> c10e330d c12b7c6c ef8f5e00 ed37f140 ed3491bc ef8f5e00 ed37f140 f0a4e0a4
> Call Trace:
> [<c10e48c8>] pnp_start_dev+0x55/0x9e
> [<c10e373a>] pnp_request_card_device+0x9b/0xbe
> [<c10e5101>] pnp_activate_dev+0x23/0x39
> [<f0a4b559>] snd_cs423x_pnpc_detect+0xe4/0x35f [snd_cs4236]
> [<c10e330d>] pnp_alloc+0xe/0x25
> [<c10e3652>] card_probe+0xba/0x107
> [<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
> [<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
> [<c103258a>] sys_init_module+0x1379/0x149b
> [<c104773a>] unmap_region+0xe5/0x100
> [<c1003d62>] syscall_call+0x7/0xb
> =======================
> Code: ff ff ff c7 85 54 01 00 00 01 00 00 00 eb 18 0f b7 12 8d 44 1b 60 43
> 83 c6 1c 0f b6 c0 e8 ce fd ff ff 83 fb 08 74 13 89 f2 03 17 <8b> 42 0c 25 00
> 01 00 20 3d 00 01 00 00 74 d5 31 db 31 f6 eb 25
> EIP: [<c10e76d9>] isapnp_set_resources+0x4d/0x132 SS:ESP 0068:e3c8fe5c
> ---[ end trace f836fd70d1d20199 ]---
>
> Rene.

2008-01-28 15:00:30

by Rene Herman

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version

On 28-01-08 15:21, Thomas Renninger wrote:

> I think I know what is going on.
> While pnpbios and pnpacpi theoretically do not have limits, isapnp has
> spec restrictions (AFAIK, I have not read this up, but taken over from
> previous implementation...).
> Therefore in isapnp I wanted to stay with:
> #define PNP_MAX_PORT 8
> #define PNP_MAX_MEM 4
> #define PNP_MAX_IRQ 2
> #define PNP_MAX_DMA 2
> but I have forgotten to malloc one portion for each at init time, or
> even better one portion as soon as one is needed.

Yup.

> As said, isapnp is more or less untested, thanks a lot for trying out.
> I will send an updated version soon.

I"m not sure of the flow of things by the way but if it makes better/nicer
code to just pretend that ISAPnP is also unlimited then I'd say to simply do
so. ISAPnP is getting obsolete anyway, not anything to optimise for...

Rene.

2008-01-28 16:04:58

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon patch 1

On Mon, 2008-01-28 at 16:00 +0100, Rene Herman wrote:
> On 28-01-08 15:21, Thomas Renninger wrote:
>
> > I think I know what is going on.
> > While pnpbios and pnpacpi theoretically do not have limits, isapnp has
> > spec restrictions (AFAIK, I have not read this up, but taken over from
> > previous implementation...).
> > Therefore in isapnp I wanted to stay with:
> > #define PNP_MAX_PORT 8
> > #define PNP_MAX_MEM 4
> > #define PNP_MAX_IRQ 2
> > #define PNP_MAX_DMA 2
> > but I have forgotten to malloc one portion for each at init time, or
> > even better one portion as soon as one is needed.
>
> Yup.
>
> > As said, isapnp is more or less untested, thanks a lot for trying out.
> > I will send an updated version soon.
>
> I"m not sure of the flow of things by the way but if it makes better/nicer
> code to just pretend that ISAPnP is also unlimited then I'd say to simply do
> so. ISAPnP is getting obsolete anyway, not anything to optimise for...
Can you try these two "on top" patches pls.
This one should fix the real cause (the "pnp: Port resource 0 not
allocated, cannot assign value" messages). The next should avoid the
NULL pointer in error case:

Also allocate memory for dependent/independent resource lists

Signed-off-by: Thomas Renninger <[email protected]>

---
drivers/pnp/manager.c | 138 ++++++++++++++++++++++----------------------------
1 file changed, 61 insertions(+), 77 deletions(-)

Index: linux-2.6.23/drivers/pnp/manager.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/manager.c
+++ linux-2.6.23/drivers/pnp/manager.c
@@ -341,99 +341,89 @@ int pnp_assign_resource(struct pnp_resou

static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
-
- if (!pnp_port_ok(dev, idx)) {
- pnp_print_assign_err("Port", idx);
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
+ struct resource res;

/* check if this resource has been manually set, if so skip */
if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
- flags = &dev->res.port_resource[idx].flags;
+ res.start = dev->res.port_resource[idx].start;
+ res.end = dev->res.port_resource[idx].end;
+ res.flags = dev->res.port_resource[idx].flags;

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IO;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_IO;
+ res.flags &= ~IORESOURCE_UNSET;

if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

- *start = rule->min;
- *end = *start + rule->size - 1;
+ res.start = rule->min;
+ res.end = res.start + rule->size - 1;

/* run through until pnp_check_port is happy */
while (!pnp_check_port(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
- return 0;
+ res.start += rule->align;
+ res.end = res.start + rule->size - 1;
+ if (res.start > rule->max || !rule->align)
+ return pnp_assign_resource(&dev->res, &res);
}
+ pnp_assign_resource(&dev->res, &res);
return 1;
}

static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
-
- if (!pnp_mem_ok(dev, idx)) {
- pnp_print_assign_err("System Memory", idx);
- return 1;
- }
+ struct resource res;

/* check if this resource has been manually set, if so skip */
if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
- flags = &dev->res.mem_resource[idx].flags;
+ res.start = dev->res.mem_resource[idx].start;
+ res.end = dev->res.mem_resource[idx].end;
+ res.flags = dev->res.mem_resource[idx].flags;

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_MEM;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_MEM;
+ res.flags &= ~IORESOURCE_UNSET;

/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
- *flags |= IORESOURCE_READONLY;
+ res.flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
- *flags |= IORESOURCE_CACHEABLE;
+ res.flags |= IORESOURCE_CACHEABLE;
if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
- *flags |= IORESOURCE_RANGELENGTH;
+ res.flags |= IORESOURCE_RANGELENGTH;
if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
- *flags |= IORESOURCE_SHADOWABLE;
+ res.flags |= IORESOURCE_SHADOWABLE;

if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

- *start = rule->min;
- *end = *start + rule->size - 1;
+ res.start = rule->min;
+ res.end = res.start + rule->size - 1;

/* run through until pnp_check_mem is happy */
while (!pnp_check_mem(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
- return 0;
+ res.start += rule->align;
+ res.end = res.start + rule->size - 1;
+ if (res.start > rule->max || !rule->align)
+ return pnp_assign_resource(&dev->res, &res);
}
+ pnp_assign_resource(&dev->res, &res);
return 1;
}

static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct resource res;
int i;

/* IRQ priority: this table is good for i386 */
@@ -441,48 +431,44 @@ static int pnp_assign_irq(struct pnp_dev
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};

- if (!pnp_irq_ok(dev, idx)) {
- pnp_print_assign_err("Irq", idx);
- return 1;
- }
-
/* check if this resource has been manually set, if so skip */
if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.irq_resource[idx].start;
- end = &dev->res.irq_resource[idx].end;
- flags = &dev->res.irq_resource[idx].flags;
+ res.start = dev->res.irq_resource[idx].start;
+ res.end = dev->res.irq_resource[idx].end;
+ res.flags = dev->res.irq_resource[idx].flags;

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IRQ;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_IRQ;
+ res.flags &= ~IORESOURCE_UNSET;

if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

/* TBD: need check for >16 IRQ */
- *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
- if (*start < PNP_IRQ_NR) {
- *end = *start;
+ res.start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+ if (res.start < PNP_IRQ_NR) {
+ res.end = res.start;
+ pnp_assign_resource(&dev->res, &res);
return 1;
}
for (i = 0; i < 16; i++) {
if (test_bit(xtab[i], rule->map)) {
- *start = *end = xtab[i];
+ res.start = res.end = xtab[i];
if (pnp_check_irq(dev, idx))
return 1;
}
}
- return 0;
+ return pnp_assign_resource(&dev->res, &res);
}

static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct resource res;
int i;

/* DMA priority: this table is good for i386 */
@@ -490,34 +476,32 @@ static void pnp_assign_dma(struct pnp_de
1, 3, 5, 6, 7, 0, 2, 4
};

- if (!pnp_dma_ok(dev, idx)) {
- pnp_print_assign_err("DMA", idx);
- return;
- }
-
/* check if this resource has been manually set, if so skip */
if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
return;

- start = &dev->res.dma_resource[idx].start;
- end = &dev->res.dma_resource[idx].end;
- flags = &dev->res.dma_resource[idx].flags;
+ res.start = dev->res.dma_resource[idx].start;
+ res.end = dev->res.dma_resource[idx].end;
+ res.flags = dev->res.dma_resource[idx].flags;

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_DMA;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_DMA;
+ res.flags &= ~IORESOURCE_UNSET;

for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
- *start = *end = xtab[i];
- if (pnp_check_dma(dev, idx))
+ res.start = res.end = xtab[i];
+ if (pnp_check_dma(dev, idx)){
+ pnp_assign_resource(&dev->res, &res);
return;
+ }
}
}
#ifdef MAX_DMA_CHANNELS
- *start = *end = MAX_DMA_CHANNELS;
+ res.start = res.end = MAX_DMA_CHANNELS;
#endif
- *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
}

/**



2008-01-28 16:05:19

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon patch 2

On Mon, 2008-01-28 at 16:00 +0100, Rene Herman wrote:
> On 28-01-08 15:21, Thomas Renninger wrote:
>
> > I think I know what is going on.
> > While pnpbios and pnpacpi theoretically do not have limits, isapnp has
> > spec restrictions (AFAIK, I have not read this up, but taken over from
> > previous implementation...).
> > Therefore in isapnp I wanted to stay with:
> > #define PNP_MAX_PORT 8
> > #define PNP_MAX_MEM 4
> > #define PNP_MAX_IRQ 2
> > #define PNP_MAX_DMA 2
> > but I have forgotten to malloc one portion for each at init time, or
> > even better one portion as soon as one is needed.
>
> Yup.
>
> > As said, isapnp is more or less untested, thanks a lot for trying out.
> > I will send an updated version soon.
>
> I"m not sure of the flow of things by the way but if it makes better/nicer
> code to just pretend that ISAPnP is also unlimited then I'd say to simply do
> so. ISAPnP is getting obsolete anyway, not anything to optimise for...

Also go the dynamic way in isapnp layer

Signed-off-by: Thomas Renninger <[email protected]>

---
drivers/pnp/isapnp/core.c | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)

Index: linux-2.6.23/drivers/pnp/isapnp/core.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/isapnp/core.c
+++ linux-2.6.23/drivers/pnp/isapnp/core.c
@@ -953,7 +953,7 @@ static int isapnp_read_resources(struct

dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
+ for (tmp = 0; pnp_port_ok(dev, tmp); tmp++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
@@ -961,8 +961,10 @@ static int isapnp_read_resources(struct
new_res.flags = IORESOURCE_IO;
if (pnp_assign_resource(res, &new_res))
pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_PORT)
+ pnp_warn("ISA exceeds spec max port");
}
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
+ for (tmp = 0; pnp_mem_ok(dev, tmp); tmp++) {
ret =
isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
if (!ret)
@@ -971,8 +973,10 @@ static int isapnp_read_resources(struct
new_res.flags = IORESOURCE_MEM;
if (pnp_assign_resource(res, &new_res))
pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_MEM)
+ pnp_warn("ISA exceeds spec max mem");
}
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
+ for (tmp = 0; pnp_irq_ok(dev, tmp); tmp++) {
ret =
(isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
8);
@@ -982,8 +986,11 @@ static int isapnp_read_resources(struct
new_res.flags = IORESOURCE_IRQ;
if (pnp_assign_resource(res, &new_res))
pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_IRQ)
+ pnp_warn("ISA exceeds spec max irq");
+
}
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
+ for (tmp = 0; pnp_dma_ok(dev, tmp); tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
@@ -992,6 +999,8 @@ static int isapnp_read_resources(struct
new_res.flags = IORESOURCE_DMA;
if (pnp_assign_resource(res, &new_res))
pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_DMA)
+ pnp_warn("ISA exceeds spec max dma");
}
}
return 0;
@@ -1017,14 +1026,14 @@ static int isapnp_set_resources(struct p
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
for (tmp = 0;
- tmp < PNP_MAX_PORT
+ pnp_port_ok(dev, tmp)
&& (res->port_resource[tmp].
flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
tmp++)
isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
res->port_resource[tmp].start);
for (tmp = 0;
- tmp < PNP_MAX_IRQ
+ pnp_irq_ok(dev, tmp)
&& (res->irq_resource[tmp].
flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
tmp++) {
@@ -1034,14 +1043,14 @@ static int isapnp_set_resources(struct p
isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
for (tmp = 0;
- tmp < PNP_MAX_DMA
+ pnp_dma_ok(dev, tmp)
&& (res->dma_resource[tmp].
flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
tmp++)
isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
res->dma_resource[tmp].start);
for (tmp = 0;
- tmp < PNP_MAX_MEM
+ pnp_mem_ok(dev, tmp)
&& (res->mem_resource[tmp].
flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
tmp++)

2008-01-28 18:07:04

by Rene Herman

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon patch 1

On 28-01-08 17:04, Thomas Renninger wrote:

> Can you try these two "on top" patches pls.

Thought I could, but my machine begs to differ...

===
pnp: the driver 'cs4236_isapnp' has been registered
cs4236_isapnp 01:01.00: driver attached
cs4236_isapnp 01:01.02: driver attached
cs4236_isapnp 01:01.03: driver attached
BUG: unable to handle kernel NULL pointer dereference at virtual address
0000000f
printing eip: c10e5136 *pde = 00000000
Oops: 0000 [#1] PREEMPT
Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
snd_page_alloc snd soundcore nfsd lockd nfs_acl sunrpc exportfs

Pid: 1370, comm: modprobe Not tainted (2.6.24-local #5)
EIP: 0060:[<c10e5136>] EFLAGS: 00010246 CPU: 0
EIP is at pnp_assign_port+0x1d/0xd5
EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: 00000001
ESI: ef8fe100 EDI: ef8f5800 EBP: 00000000 ESP: ed3b4e08
DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
Process modprobe (pid: 1370, ti=ed3b4000 task=ed35c000 task.ti=ed3b4000)
Stack: ed3b4e34 c108ac94 ed3b4e34 ed3c1b10 00000000 efa4e360 c108b88b ef8fe100
00000000 ef8f5800 ef82ee40 c10e5360 00000001 ef8f5964 00000000 00000000
00000000 00000000 00000000 ef805ea0 ef8f5800 ef863c80 00000001 ed373400
Call Trace:
[<c108ac94>] sysfs_addrm_start+0x36/0x81
[<c108b88b>] sysfs_create_link+0xd0/0x111
[<c10e5360>] pnp_assign_resources+0x172/0x23a
[<c10e548f>] pnp_auto_config_dev+0x67/0xa6
[<c10e373a>] pnp_request_card_device+0x9b/0xbe
[<c10e54e1>] pnp_activate_dev+0x13/0x3a
[<f0a4b559>] snd_cs423x_pnpc_detect+0xe4/0x35f [snd_cs4236]
[<c10e330d>] pnp_alloc+0xe/0x25
[<c10e3652>] card_probe+0xba/0x107
[<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
[<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
[<c103258a>] sys_init_module+0x1379/0x149b
[<c104773a>] unmap_region+0xe5/0x100
[<c1003d62>] syscall_call+0x7/0xb
=======================
Code: ba 01 00 00 00 83 c4 1c 89 d0 5b 5e 5f c3 55 89 cd 57 89 c7 56 89 d6
ba 01 00 00 00 53 6b d9 1c 83 ec 1c 89 d8 03 87 64 01 00 00 <f6> 40 0f 40 0f
84 a4 00 00 00 8b 00 8b 97 64 01 00 00 0f b6 4e
EIP: [<c10e5136>] pnp_assign_port+0x1d/0xd5 SS:ESP 0068:ed3b4e08
---[ end trace d756fac577a9260d ]---

Rene.

2008-01-28 19:16:56

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon patch 3

On Mon, 2008-01-28 at 19:07 +0100, Rene Herman wrote:
> On 28-01-08 17:04, Thomas Renninger wrote:
>
> > Can you try these two "on top" patches pls.
>
> Thought I could, but my machine begs to differ...
>
> ===
> pnp: the driver 'cs4236_isapnp' has been registered
> cs4236_isapnp 01:01.00: driver attached
> cs4236_isapnp 01:01.02: driver attached
> cs4236_isapnp 01:01.03: driver attached
> BUG: unable to handle kernel NULL pointer dereference at virtual address
> 0000000f
> printing eip: c10e5136 *pde = 00000000
> Oops: 0000 [#1] PREEMPT
> Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
> snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
> snd_page_alloc snd soundcore nfsd lockd nfs_acl sunrpc exportfs
>
> Pid: 1370, comm: modprobe Not tainted (2.6.24-local #5)
> EIP: 0060:[<c10e5136>] EFLAGS: 00010246 CPU: 0
> EIP is at pnp_assign_port+0x1d/0xd5
> EAX: 00000000 EBX: 00000000 ECX: 00000000 EDX: 00000001
> ESI: ef8fe100 EDI: ef8f5800 EBP: 00000000 ESP: ed3b4e08
> DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
> Process modprobe (pid: 1370, ti=ed3b4000 task=ed35c000 task.ti=ed3b4000)
> Stack: ed3b4e34 c108ac94 ed3b4e34 ed3c1b10 00000000 efa4e360 c108b88b ef8fe100
> 00000000 ef8f5800 ef82ee40 c10e5360 00000001 ef8f5964 00000000 00000000
> 00000000 00000000 00000000 ef805ea0 ef8f5800 ef863c80 00000001 ed373400
> Call Trace:
> [<c108ac94>] sysfs_addrm_start+0x36/0x81
> [<c108b88b>] sysfs_create_link+0xd0/0x111
> [<c10e5360>] pnp_assign_resources+0x172/0x23a
> [<c10e548f>] pnp_auto_config_dev+0x67/0xa6
> [<c10e373a>] pnp_request_card_device+0x9b/0xbe
> [<c10e54e1>] pnp_activate_dev+0x13/0x3a
> [<f0a4b559>] snd_cs423x_pnpc_detect+0xe4/0x35f [snd_cs4236]
> [<c10e330d>] pnp_alloc+0xe/0x25
> [<c10e3652>] card_probe+0xba/0x107
> [<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
> [<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
> [<c103258a>] sys_init_module+0x1379/0x149b
> [<c104773a>] unmap_region+0xe5/0x100
> [<c1003d62>] syscall_call+0x7/0xb
> =======================
> Code: ba 01 00 00 00 83 c4 1c 89 d0 5b 5e 5f c3 55 89 cd 57 89 c7 56 89 d6
> ba 01 00 00 00 53 6b d9 1c 83 ec 1c 89 d8 03 87 64 01 00 00 <f6> 40 0f 40 0f
> 84 a4 00 00 00 8b 00 8b 97 64 01 00 00 0f b6 4e
> EIP: [<c10e5136>] pnp_assign_port+0x1d/0xd5 SS:ESP 0068:ed3b4e08
> ---[ end trace d756fac577a9260d ]---
This was more a step backward, hopefully this one (on top), gets the
area bugfree?

Differ already accessed and newly set resource options

Signed-off-by: Thomas Renninger <[email protected]>


---
drivers/pnp/manager.c | 49 +++++++++++++++++++++++++++++++++----------------
1 file changed, 33 insertions(+), 16 deletions(-)

Index: linux-2.6.23/drivers/pnp/manager.c
===================================================================
--- linux-2.6.23.orig/drivers/pnp/manager.c
+++ linux-2.6.23/drivers/pnp/manager.c
@@ -344,12 +344,20 @@ static int pnp_assign_port(struct pnp_de
struct resource res;

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_port_ok(dev, idx) && !(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- res.start = dev->res.port_resource[idx].start;
- res.end = dev->res.port_resource[idx].end;
- res.flags = dev->res.port_resource[idx].flags;
+ if (pnp_port_ok(dev, idx)) {
+ /* This resource index already got some values assigned,
+ take them as init */
+ res.start = dev->res.port_resource[idx].start;
+ res.end = dev->res.port_resource[idx].end;
+ res.flags = dev->res.port_resource[idx].flags;
+ } else
+ /* This index in the table does not exist, initialize the new
+ resource and be carefuly to never access
+ dev->res.port_resource[idx] */
+ pnp_init_io(&res);

/* set the initial values */
res.flags |= rule->flags | IORESOURCE_IO;
@@ -380,12 +388,15 @@ static int pnp_assign_mem(struct pnp_dev
struct resource res;

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_mem_ok(dev, idx) && !(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- res.start = dev->res.mem_resource[idx].start;
- res.end = dev->res.mem_resource[idx].end;
- res.flags = dev->res.mem_resource[idx].flags;
+ if (pnp_mem_ok(dev, idx)) {
+ res.start = dev->res.mem_resource[idx].start;
+ res.end = dev->res.mem_resource[idx].end;
+ res.flags = dev->res.mem_resource[idx].flags;
+ } else
+ pnp_init_mem(&res);

/* set the initial values */
res.flags |= rule->flags | IORESOURCE_MEM;
@@ -432,12 +443,15 @@ static int pnp_assign_irq(struct pnp_dev
};

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_irq_ok(dev, idx) && !(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- res.start = dev->res.irq_resource[idx].start;
- res.end = dev->res.irq_resource[idx].end;
- res.flags = dev->res.irq_resource[idx].flags;
+ if (pnp_irq_ok(dev, idx)) {
+ res.start = dev->res.irq_resource[idx].start;
+ res.end = dev->res.irq_resource[idx].end;
+ res.flags = dev->res.irq_resource[idx].flags;
+ } else
+ pnp_init_irq(&res);

/* set the initial values */
res.flags |= rule->flags | IORESOURCE_IRQ;
@@ -477,12 +491,15 @@ static void pnp_assign_dma(struct pnp_de
};

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_dma_ok(dev, idx) && !(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
return;

- res.start = dev->res.dma_resource[idx].start;
- res.end = dev->res.dma_resource[idx].end;
- res.flags = dev->res.dma_resource[idx].flags;
+ if (pnp_dma_ok(dev, idx)) {
+ res.start = dev->res.dma_resource[idx].start;
+ res.end = dev->res.dma_resource[idx].end;
+ res.flags = dev->res.dma_resource[idx].flags;
+ } else
+ pnp_init_dma(&res);

/* set the initial values */
res.flags |= rule->flags | IORESOURCE_DMA;

2008-01-28 21:12:18

by Rene Herman

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon patch 3

diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index f1fdd96..21719e5 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -219,13 +219,14 @@ int pnp_check_port(struct pnp_dev *dev, int idx)
struct pnp_dev *tdev;
resource_size_t *port, *end, *tport, *tend;

- port = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
-
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.port_resource[idx].flags))
+ if (!pnp_port_ok(dev, idx) ||
+ cannot_compare(dev->res.port_resource[idx].flags))
return 1;

+ port = &dev->res.port_resource[idx].start;
+ end = &dev->res.port_resource[idx].end;
+
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if (!dev->active) {
@@ -277,13 +278,14 @@ int pnp_check_mem(struct pnp_dev *dev, int idx)
struct pnp_dev *tdev;
resource_size_t *addr, *end, *taddr, *tend;

- addr = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
-
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.mem_resource[idx].flags))
+ if (!pnp_mem_ok(dev, idx) ||
+ cannot_compare(dev->res.mem_resource[idx].flags))
return 1;

+ addr = &dev->res.mem_resource[idx].start;
+ end = &dev->res.mem_resource[idx].end;
+
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if (!dev->active) {
@@ -338,12 +340,15 @@ int pnp_check_irq(struct pnp_dev *dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
- resource_size_t *irq = &dev->res.irq_resource[idx].start;
+ resource_size_t *irq;

/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.irq_resource[idx].flags))
+ if (!pnp_irq_ok(dev, idx) ||
+ cannot_compare(dev->res.irq_resource[idx].flags))
return 1;

+ irq = &dev->res.irq_resource[idx].start;
+
/* check if the resource is valid */
if (*irq < 0 || *irq > 15)
return 0;
@@ -407,12 +412,15 @@ int pnp_check_dma(struct pnp_dev *dev, int idx)
#ifndef CONFIG_IA64
int tmp;
struct pnp_dev *tdev;
- resource_size_t *dma = &dev->res.dma_resource[idx].start;
+ resource_size_t *dma;

/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.dma_resource[idx].flags))
+ if (!pnp_dma_ok(dev, idx) ||
+ cannot_compare(dev->res.dma_resource[idx].flags))
return 1;

+ dma = &dev->res.dma_resource[idx].start;
+
/* check if the resource is valid */
if (*dma < 0 || *dma == 4 || *dma > 7)
return 0;


Attachments:
foo.diff (2.56 kB)

2008-01-29 14:19:11

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - working version - Addon debug patch 4

On Mon, 2008-01-28 at 22:12 +0100, Rene Herman wrote:
> On 28-01-08 20:12, Thomas Renninger wrote:
>
> > This was more a step backward, hopefully this one (on top), gets the
> > area bugfree?
>
> I'm afraid not. Next oops in pnp_check_port(). The attached lets it get past
> that point but _then_ things fall apart a little bit further on again which
> seems to mean it's something a bit more fundamental. Should pnp_check_* even
> be called without any initialised resources?
>
> Without the attached:
>
> ===
> pnp: the driver 'cs4236_isapnp' has been registered
> cs4236_isapnp 01:01.00: driver attached
> cs4236_isapnp 01:01.02: driver attached
> cs4236_isapnp 01:01.03: driver attached
> BUG: unable to handle kernel NULL pointer dereference at virtual address
> 0000000c
> printing eip: c10e4365 *pde = 00000000
> Oops: 0000 [#1] PREEMPT
> Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
> snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
> snd soundcore s
> nd_page_alloc nfsd lockd nfs_acl sunrpc exportfs
>
> Pid: 1350, comm: modprobe Not tainted (2.6.24-local #6)
> EIP: 0060:[<c10e4365>] EFLAGS: 00010246 CPU: 0
> EIP is at pnp_check_port+0x15/0x125
> EAX: ef8f5800 EBX: 00000000 ECX: 00000000 EDX: 00000000
> ESI: ef8f5800 EDI: 00000000 EBP: ef8f5800 ESP: e447edec
> DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
> Process modprobe (pid: 1350, ti=e447e000 task=ed35f4c0 task.ti=e447e000)
> Stack: 00000000 e447d900 c108ab97 ef8fe100 ef8f5800 00000000 ef82ae40 c10e5295
> 00000534 00000537 00000000 40000101 efa4e360 c108b88b e4462180 ef8fe100
> 00000000 ef8f5800 c10e5426 00000001 ef8f5964 00000000 00000000 00000000
> Call Trace:
> [<c108ab97>] sysfs_find_dirent+0x13/0x23
> [<c10e5295>] pnp_assign_port+0xe5/0x104
> [<c108b88b>] sysfs_create_link+0xd0/0x111
> [<c10e5426>] pnp_assign_resources+0x172/0x23a
> [<c10e5555>] pnp_auto_config_dev+0x67/0xa6
> [<c10e373a>] pnp_request_card_device+0x9b/0xbe
> [<c10e55a7>] pnp_activate_dev+0x13/0x3c
> [<f0a4b559>] snd_cs423x_pnpc_detect+0xe4/0x35f [snd_cs4236]
> [<c10e330d>] pnp_alloc+0xe/0x25
> [<c10e3652>] card_probe+0xba/0x107
> [<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
> [<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
> [<c103258a>] sys_init_module+0x1379/0x149b
> [<c104773a>] unmap_region+0xe5/0x100
> [<c1003d62>] syscall_call+0x7/0xb
> =======================
> Code: ac 29 c1 75 a7 b8 01 00 00 00 eb 02 31 c0 83 c4 0c 5b 5e 5f 5d c3 55
> 89 c5 57 56 53 6b da 1c 83 ec 0c 89 14 24 03 98 64 01 00 00 <f7> 43 0c 00 00
> 00 30 0
> f 85 f2 00 00 00 83 b8 54 01 00 00 00 75
> EIP: [<c10e4365>] pnp_check_port+0x15/0x125 SS:ESP 0068:e447edec
> ---[ end trace 149e6ce75dd3870f ]---
> ===
>
> With the attached:
>
> ===
> pnp: the driver 'cs4236_isapnp' has been registered
> cs4236_isapnp 01:01.00: driver attached
> cs4236_isapnp 01:01.02: driver attached
> cs4236_isapnp 01:01.03: driver attached
> pnp: Port allocate: ed366400 - ed369500; Allocated: 448 bytes, size
> ofstruct: 28 - allocated ports: 8
> pnp: Dma allocate: ed276a80 - ed2776c0; Allocated: 112 bytes, size ofstruct:
> 28 - allocated dmas: 2
> cs4236_isapnp 01:01.00: activated
> BUG: unable to handle kernel NULL pointer dereference at virtual address
> 00000000
> printing eip: f0a4b5a8 *pde = 00000000
> Oops: 0000 [#1] PREEMPT
> Modules linked in: snd_cs4236 snd_opl3_lib snd_hwdep snd_cs4236_lib
> snd_mpu401_uart snd_rawmidi snd_seq_device snd_cs4231_lib snd_pcm snd_timer
> snd soundcore snd_page_alloc nfsd lockd nfs_acl sunrpc exportfs
>
> Pid: 1348, comm: modprobe Not tainted (2.6.24-local #9)
> EIP: 0060:[<f0a4b5a8>] EFLAGS: 00010202 CPU: 0
> EIP is at snd_cs423x_pnpc_detect+0x133/0x35f [snd_cs4236]
> EAX: 00000000 EBX: ef8f5800 ECX: 00000220 EDX: 00000001
> ESI: 00000000 EDI: 00000534 EBP: ed338200 ESP: ed3cfe90
> DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
> Process modprobe (pid: 1348, ti=ed3cf000 task=ed2c79f0 task.ti=ed3cf000)
> Stack: 00000286 00000001 f0a4d780 c10e330d c12b7c6c ef8f5e00 ed26fe80 ed3383bc
> ef8f5e00 ed26fe80 f0a4e0a4 00000003 c10e3652 f0a4d740 ef8f5600 f0a4d740
> efa4f514 f0a8aa4c 00000000 c10e3b75 00000001 f0a4e440 f08de02f ed338fc4
> Call Trace:
> [<c10e330d>] pnp_alloc+0xe/0x25
> [<c10e3652>] card_probe+0xba/0x107
> [<c10e3b75>] pnp_register_card_driver+0xa3/0xb3
> [<f08de02f>] alsa_card_cs423x_init+0x2f/0x4f [snd_cs4236]
> [<c103258a>] sys_init_module+0x1379/0x149b
> [<c104773a>] unmap_region+0xe5/0x100
> [<c1003d62>] syscall_call+0x7/0xb
> =======================
> Code: d6 a4 f0 7e 10 8b 83 64 01 00 00 8b 40 1c 89 04 b5 60 d6 a4 f0 8b 83
> 64 01 00 00 8b 48 38 89 0c b5 40 d6 a4 f0 8b 83 7c 01 00 00 <8b> 00 89 04 b5
> 20 d6 a4 f0 8b 83 74 01 00 00 8b 00 89 04 b5 e0
> EIP: [<f0a4b5a8>] snd_cs423x_pnpc_detect+0x133/0x35f [snd_cs4236] SS:ESP
> 0068:ed3cfe90
> ---[ end trace 9f2b1188efb740f7 ]---
> ===
>
> For reference:
>
> # cat /sys/bus/pnp/devices/01\:01.00/options
> Dependent: 01 - Priority preferred
> port 0x534-0x534, align 0x3, size 0x4, 16-bit address decoding
> port 0x388-0x388, align 0x7, size 0x4, 16-bit address decoding
> port 0x220-0x220, align 0x1f, size 0x10, 16-bit address decoding
> irq 5 High-Edge
> dma 1 8-bit master byte-count type-F
> dma 0 8-bit master byte-count type-F

This is without these patches and same/similar kernel?
I expect that ports and dmas are found, see allocations above.
But for some reason the irq is not.
Now comes a drawback of my patch... One needs to go through all pnp
layer using drivers and make sure they invoke
pnp_{port,mem,irq,dma}_valid (or at least _ok) macros before they
actually access the resource via e.g. pnp_irq or pnp_port_start...
I wonder where the irq 5 above comes from. Maybe there is another bug or
that is what the pnp_resource_change and friends was for, maybe the
driver somehow falls back to 5 if no sane irq is set by BIOS read
values.

This patch may be a bit too much of sanity checking or maybe a similar
approach (without the pnp_warn) even is the way to go, instead of
checking all pnp using drivers?

Can you try this debug patch out, pls. Hopefully the NULL pointer
exceptions are finally gone?


Sanity check every resource access

Signed-off-by: Thomas Renninger <[email protected]>

---
include/linux/pnp.h | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)

Index: linux-2.6.23/include/linux/pnp.h
===================================================================
--- linux-2.6.23.orig/include/linux/pnp.h
+++ linux-2.6.23/include/linux/pnp.h
@@ -33,10 +33,13 @@ struct pnp_dev;

#define pnp_port_ok(dev,bar) ((dev)->res.allocated_ports > (bar))

-#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
-#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
-#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
-#define pnp_port_valid(dev,bar) \
+#define pnp_port_start(dev,bar) (pnp_port_ok((dev),(bar)) ? (dev)->res.port_resource[(bar)].start \
+ : pnp_warn("Port start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_end(dev,bar) (pnp_port_ok((dev),(bar)) ? (dev)->res.port_resource[(bar)].end \
+ : pnp_warn("Port end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_flags(dev,bar) (pnp_port_ok((dev),(bar)) ? (dev)->res.port_resource[(bar)].flags \
+ : pnp_warn("Port flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_valid(dev,bar) \
(pnp_port_ok((dev),(bar)) && \
((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
== IORESOURCE_IO))
@@ -49,9 +52,12 @@ struct pnp_dev;
pnp_port_start((dev),(bar)) + 1))

#define pnp_mem_ok(dev,bar) ((dev)->res.allocated_mems > (bar))
-#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
-#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
-#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
+#define pnp_mem_start(dev,bar) (pnp_mem_ok((dev),(bar)) ? (dev)->res.mem_resource[(bar)].start \
+ : pnp_warn("Mem start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_mem_end(dev,bar) (pnp_mem_ok((dev),(bar)) ? (dev)->res.mem_resource[(bar)].end \
+ : pnp_warn("Mem end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_mem_flags(dev,bar) (pnp_mem_ok((dev),(bar)) ? (dev)->res.mem_resource[(bar)].flags \
+ : pnp_warn("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_mem_valid(dev,bar) \
(pnp_mem_ok((dev),(bar)) && \
((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
@@ -65,16 +71,20 @@ struct pnp_dev;
pnp_mem_start((dev),(bar)) + 1))

#define pnp_irq_ok(dev,bar) ((dev)->res.allocated_irqs > (bar))
-#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
-#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
+#define pnp_irq(dev,bar) (pnp_irq_ok((dev),(bar)) ? (dev)->res.irq_resource[(bar)].start \
+ : pnp_warn("Irq start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_irq_flags(dev,bar) (pnp_irq_ok((dev),(bar)) ? (dev)->res.irq_resource[(bar)].flags \
+ : pnp_warn("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_irq_valid(dev,bar) \
(pnp_irq_ok((dev),(bar)) && \
((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
== IORESOURCE_IRQ))

#define pnp_dma_ok(dev,bar) ((dev)->res.allocated_dmas > (bar))
-#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
-#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
+#define pnp_dma(dev,bar) (pnp_dma_ok((dev),(bar)) ? (dev)->res.dma_resource[(bar)].start \
+ : pnp_warn("Dma start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_dma_flags(dev,bar) (pnp_dma_ok((dev),(bar)) ? (dev)->res.dma_resource[(bar)].flags \
+ : pnp_warn("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_dma_valid(dev,bar) \
(pnp_dma_ok((dev),(bar)) && \
((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \

2008-02-05 18:20:32

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - Yet another Version

On Mon, 2008-01-28 at 22:12 +0100, Rene Herman wrote:
> On 28-01-08 20:12, Thomas Renninger wrote:
>
> > This was more a step backward, hopefully this one (on top), gets the
> > area bugfree?

This one includes findings from tests with Rene on a isa system.
It handles possible NULL pointers and checks them inside the
pnp_{mem,dma,irq,port}_{start,end,flags}. Which is a must for now with
dynamic allocated resources. I first thought this could be checked
inside the drivers with pnp_*_valid, but for now this is safer and
easier to do.

I also integrated a suggestion from Bjorn and eliminated the not needed
pnp_*_ok macros and used pnp_*_valid instead.
Testcompiled with one example .config. I still build with different
configs, I will let you know if anything did not build tomorrow (if not
it builds).

------------

Allocate pnp resources dynamically via krealloc

Latest BIOS ACPI PNP device resource descriptions may have (especially on the
general device PNP0c02) more than 20 IO port resources.
Reserve the space in a static array wastes a lot of memory on every PNP device
and is not a real option as the number of IO ports could be much greater than
20.

This approach allocates the memory for PNP resources at runtime.
The memory is reallocated in e.g. 8 (for IO port) resource portions.
That means that the previously allocated pointers will get a new address.
Therefore this address must not be stored and/or used as long as krealloc
might still allocate new resources.
>From what I have seen, there is a patch in -mm that gets rid of
registering resources automatically and pass the pointers from
pnp_resource_table to request_region.
While this should still work (only disabled devices where the regions
should have been unregistered should be modifyable) it is potential
dangereous: once you realloc pnp_resource_table pointers you end up
with invalid pointers in the kernel/resource.c implemented list.
Finding this could get difficult as you get really ugly phenomenons with
corrupted memory...


The patch also needs another patch from Rene Herman:
"[PATCH] sound/isa: kill pnp_resource_change."
Sent to the alsa-devel list and it's already included in Takashi's tree
for 2.6.25 inclusion.
The function pnp_resource_change is a nop now and immediately returns to avoid
compile errors. It can be removed as soon as everything is merged together.

This has been tested on rather new machines on i386 and x86_64.
The first with pnpbios also compiled in and forced a test with pnpacpi=off.

isapnp was partly tested by Rene. Whether this latest version works there
still needs a test.
Also the sysfs interface is rather untested.

I tried to play a bit with the sysfs interface and wanted override
resources without much success:
Unloaded parport_pc driver, then the corresponding pnp device changed state
from active to disabled and now I should have been able to modify BIOS
settings, but it did not work. I expect this is rather unused and could have
been broken before and I did not want to loose more time with it.
Maybe someone else knows more here.


---
drivers/pnp/core.c | 2
drivers/pnp/interface.c | 44 ++-
drivers/pnp/isapnp/core.c | 58 +++-
drivers/pnp/manager.c | 549 +++++++++++++++++++++++++++++++----------
drivers/pnp/pnpacpi/rsparser.c | 151 +++++------
drivers/pnp/pnpbios/rsparser.c | 112 ++++----
drivers/pnp/resource.c | 16 -
drivers/pnp/support.c | 11
drivers/pnp/system.c | 4
include/linux/pnp.h | 78 +++--
10 files changed, 694 insertions(+), 331 deletions(-)

Index: linux-acpi-2.6/drivers/pnp/core.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/core.c
+++ linux-acpi-2.6/drivers/pnp/core.c
@@ -129,6 +129,7 @@ int __pnp_add_device(struct pnp_dev *dev
return ret;

pnp_interface_attach_device(dev);
+ pnp_dump_resources(dev);
return 0;
}

@@ -148,6 +149,7 @@ int pnp_add_device(struct pnp_dev *dev)
dev->dev.parent = &dev->protocol->dev;
sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
dev->number);
+ pnp_dbg("Adding device %s - %s", dev->name, dev->dev.bus_id);
ret = __pnp_add_device(dev);
if (ret)
return ret;
Index: linux-acpi-2.6/drivers/pnp/interface.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/interface.c
+++ linux-acpi-2.6/drivers/pnp/interface.c
@@ -264,7 +264,7 @@ static ssize_t pnp_show_current_resource
else
pnp_printf(buffer, "disabled\n");

- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_valid(dev, i); i++) {
if (pnp_port_valid(dev, i)) {
pnp_printf(buffer, "io");
if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
@@ -277,7 +277,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
+ for (i = 0; pnp_mem_valid(dev, i); i++) {
if (pnp_mem_valid(dev, i)) {
pnp_printf(buffer, "mem");
if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
@@ -290,7 +290,7 @@ static ssize_t pnp_show_current_resource
i));
}
}
- for (i = 0; i < PNP_MAX_IRQ; i++) {
+ for (i = 0; pnp_irq_valid(dev, i); i++) {
if (pnp_irq_valid(dev, i)) {
pnp_printf(buffer, "irq");
if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
@@ -300,7 +300,7 @@ static ssize_t pnp_show_current_resource
(unsigned long long)pnp_irq(dev, i));
}
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
+ for (i = 0; pnp_dma_valid(dev, i); i++) {
if (pnp_dma_valid(dev, i)) {
pnp_printf(buffer, "dma");
if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
@@ -381,6 +381,13 @@ pnp_set_current_resources(struct device
buf += 2;
while (isspace(*buf))
++buf;
+ if (!pnp_port_valid(dev, nport)) {
+ buf++;
+ pnp_err("Cannot manually set port"
+ "resource %d for device %s",
+ nport, dev->name);
+ continue;
+ }
dev->res.port_resource[nport].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -397,14 +404,19 @@ pnp_set_current_resources(struct device
dev->res.port_resource[nport].flags =
IORESOURCE_IO;
nport++;
- if (nport >= PNP_MAX_PORT)
- break;
continue;
}
if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_mem_valid(dev, nmem)) {
+ buf++;
+ pnp_err("Cannot manually set mem "
+ "resource %d for device %s",
+ nmem, dev->name);
+ continue;
+ }
dev->res.mem_resource[nmem].start =
simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
@@ -421,36 +433,44 @@ pnp_set_current_resources(struct device
dev->res.mem_resource[nmem].flags =
IORESOURCE_MEM;
nmem++;
- if (nmem >= PNP_MAX_MEM)
- break;
continue;
}
if (!strnicmp(buf, "irq", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_irq_valid(dev, nirq)) {
+ buf++;
+ pnp_err("Cannot manually set irq "
+ "resource %d for device %s",
+ nirq, dev->name);
+ continue;
+ }
dev->res.irq_resource[nirq].start =
dev->res.irq_resource[nirq].end =
simple_strtoul(buf, &buf, 0);
dev->res.irq_resource[nirq].flags =
IORESOURCE_IRQ;
nirq++;
- if (nirq >= PNP_MAX_IRQ)
- break;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
+ if (!pnp_dma_valid(dev, ndma)) {
+ buf++;
+ pnp_err("Cannot manually set dma "
+ "resource %d for device %s",
+ ndma, dev->name);
+ continue;
+ }
dev->res.dma_resource[ndma].start =
dev->res.dma_resource[ndma].end =
simple_strtoul(buf, &buf, 0);
dev->res.dma_resource[ndma].flags =
IORESOURCE_DMA;
ndma++;
- if (ndma >= PNP_MAX_DMA)
- break;
continue;
}
break;
Index: linux-acpi-2.6/drivers/pnp/isapnp/core.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/isapnp/core.c
+++ linux-acpi-2.6/drivers/pnp/isapnp/core.c
@@ -42,6 +42,7 @@
#include <linux/init.h>
#include <linux/isapnp.h>
#include <linux/mutex.h>
+
#include <asm/io.h>

#if 0
@@ -65,6 +66,12 @@ module_param(isapnp_verbose, int, 0);
MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
MODULE_LICENSE("GPL");

+/* ISAPNP is restricted to these limits by spec */
+#define PNP_MAX_PORT 8
+#define PNP_MAX_MEM 4
+#define PNP_MAX_IRQ 2
+#define PNP_MAX_DMA 2
+
#define _PIDXR 0x279
#define _PNPWRP 0xa79

@@ -942,41 +949,58 @@ static int isapnp_read_resources(struct
struct pnp_resource_table *res)
{
int tmp, ret;
+ struct resource new_res;

dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
+ for (tmp = 0; pnp_port_valid(dev, tmp); tmp++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
- res->port_resource[tmp].start = ret;
- res->port_resource[tmp].flags = IORESOURCE_IO;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_IO;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_PORT)
+ pnp_warn("ISA exceeds spec max port");
}
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
+ for (tmp = 0; pnp_mem_valid(dev, tmp); tmp++) {
ret =
isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
if (!ret)
continue;
- res->mem_resource[tmp].start = ret;
- res->mem_resource[tmp].flags = IORESOURCE_MEM;
+ new_res.start = ret;
+ new_res.flags = IORESOURCE_MEM;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_MEM)
+ pnp_warn("ISA exceeds spec max mem");
}
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
+ for (tmp = 0; pnp_irq_valid(dev, tmp); tmp++) {
ret =
(isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
8);
if (!ret)
continue;
- res->irq_resource[tmp].start =
- res->irq_resource[tmp].end = ret;
- res->irq_resource[tmp].flags = IORESOURCE_IRQ;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_IRQ;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_IRQ)
+ pnp_warn("ISA exceeds spec max irq");
+
}
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
+ for (tmp = 0; pnp_dma_valid(dev, tmp); tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
res->dma_resource[tmp].start =
- res->dma_resource[tmp].end = ret;
- res->dma_resource[tmp].flags = IORESOURCE_DMA;
+ new_res.start = new_res.end = ret;
+ new_res.flags = IORESOURCE_DMA;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ if (tmp > PNP_MAX_DMA)
+ pnp_warn("ISA exceeds spec max dma");
}
}
return 0;
@@ -1002,14 +1026,14 @@ static int isapnp_set_resources(struct p
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
for (tmp = 0;
- tmp < PNP_MAX_PORT
+ pnp_port_valid(dev, tmp)
&& (res->port_resource[tmp].
flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
tmp++)
isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
res->port_resource[tmp].start);
for (tmp = 0;
- tmp < PNP_MAX_IRQ
+ pnp_irq_valid(dev, tmp)
&& (res->irq_resource[tmp].
flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
tmp++) {
@@ -1019,14 +1043,14 @@ static int isapnp_set_resources(struct p
isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
}
for (tmp = 0;
- tmp < PNP_MAX_DMA
+ pnp_dma_valid(dev, tmp)
&& (res->dma_resource[tmp].
flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
tmp++)
isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
res->dma_resource[tmp].start);
for (tmp = 0;
- tmp < PNP_MAX_MEM
+ pnp_mem_valid(dev, tmp)
&& (res->mem_resource[tmp].
flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
tmp++)
Index: linux-acpi-2.6/drivers/pnp/manager.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/manager.c
+++ linux-acpi-2.6/drivers/pnp/manager.c
@@ -14,104 +14,427 @@
#include <linux/bitmap.h>
#include "base.h"

+/* Defines the amount of struct resources that will get (re-)alloced
+ * if the resource table runs out of allocated ports/irqs/dma/mems
+ */
+#define PNP_ALLOC_PORT 8
+#define PNP_ALLOC_MEM 4
+#define PNP_ALLOC_IRQ 2
+#define PNP_ALLOC_DMA 2
+
DECLARE_MUTEX(pnp_res_mutex);

-static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
+#ifdef CONFIG_PNP_DEBUG
+void pnp_dump_resources(struct pnp_dev *dev)
{
- resource_size_t *start, *end;
- unsigned long *flags;
-
- if (idx >= PNP_MAX_PORT) {
- dev_err(&dev->dev, "too many I/O port resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
+ int i;
+ pnp_dbg("Resource table dump:");
+ pnp_dbg("Allocted: ports: %d [%p - %p]",
+ dev->res.allocated_ports, dev->res.port_resource,
+ dev->res.port_resource + (dev->res.allocated_ports *
+ sizeof(struct resource)));
+ for (i = 0; pnp_port_valid(dev, i); i++) {
+ pnp_dbg("Port %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_port_start(dev, i),
+ (unsigned long)pnp_port_end(dev, i),
+ pnp_port_flags(dev, i));
+ }
+ pnp_dbg("Allocted: mems: %d [%p - %p]",
+ dev->res.allocated_mems, dev->res.mem_resource,
+ dev->res.mem_resource + (dev->res.allocated_mems *
+ sizeof(struct resource)));
+ for (i = 0; pnp_mem_valid(dev, i); i++) {
+ pnp_dbg("Mem %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_mem_start(dev, i),
+ (unsigned long)pnp_mem_end(dev, i),
+ pnp_mem_flags(dev, i));
+ }
+ pnp_dbg("Allocted: irqs: %d [%p - %p]",
+ dev->res.allocated_irqs, dev->res.irq_resource,
+ dev->res.irq_resource + (dev->res.allocated_irqs *
+ sizeof(struct resource)));
+ for (i = 0; pnp_irq_valid(dev, i); i++) {
+ pnp_dbg("Irq %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_irq(dev, i),
+ pnp_irq_flags(dev, i));
+ }
+ pnp_dbg("Allocted: dmas: %d [%p - %p]",
+ dev->res.allocated_dmas, dev->res.dma_resource,
+ dev->res.dma_resource + (dev->res.allocated_dmas *
+ sizeof(struct resource)));
+ for (i = 0; pnp_dma_valid(dev, i); i++) {
+ pnp_dbg("Dma %d: start: 0x%lx - flags: %lu", i,
+ (unsigned long)pnp_dma(dev, i),
+ pnp_dma_flags(dev, i));
}
+}
+#endif
+
+static void pnp_init_io(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_mem(struct resource *res)
+{
+ res->name = NULL;
+ res->start = 0;
+ res->end = 0;
+ res->flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_irq(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+static void pnp_init_dma(struct resource *res)
+{
+ res->name = NULL;
+ res->start = -1;
+ res->end = -1;
+ res->flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+}
+
+/****************************************************************
+ *
+ * pnp_alloc_{port,dma,irq,mem}
+ *
+ * These functions must only be when a device is not active and
+ * can therefore not have any resources requested via kernel/resource.c
+ * If the pnp resource table has not enough (or none) resources of
+ * a specific type allocated, the memory of the array is increased
+ * via krealloc, which results in changed pointers of all already
+ * allocated struct resources in the table.
+ * This would invalidate the addresses passed to request/insert_resource
+ */
+
+static int pnp_alloc_port(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->port_resource,
+ (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->port_resource = ret;
+
+ res->allocated_ports += PNP_ALLOC_PORT;
+ for (i = res->allocated_ports - PNP_ALLOC_PORT;
+ i < res->allocated_ports; i++)
+ pnp_init_io(&res->port_resource[i]);
+
+ pnp_dbg("Port allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated ports: %d",
+ res->port_resource,
+ res->port_resource
+ + (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) (sizeof(struct resource) * res->allocated_ports)
+ + (sizeof(struct resource) * PNP_ALLOC_PORT),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_ports);
+
+ return 0;
+}
+
+static int pnp_alloc_mem(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->mem_resource,
+ (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->mem_resource = ret;
+
+ res->allocated_mems += PNP_ALLOC_MEM;
+
+ for (i = res->allocated_mems - PNP_ALLOC_MEM; i < res->allocated_mems;
+ i++)
+ pnp_init_mem(&res->mem_resource[i]);
+
+ pnp_dbg("Mem allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated mems: %d",
+ res->mem_resource,
+ res->mem_resource
+ + (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) (sizeof(struct resource) * res->allocated_mems)
+ + (sizeof(struct resource) * PNP_ALLOC_MEM),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_mems);
+
+ return 0;
+}
+
+static int pnp_alloc_irq(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->irq_resource,
+ (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->irq_resource = ret;
+
+ res->allocated_irqs += PNP_ALLOC_IRQ;
+ for (i = res->allocated_irqs - PNP_ALLOC_IRQ; i < res->allocated_irqs;
+ i++)
+ pnp_init_irq(&res->irq_resource[i]);
+
+ pnp_dbg("Irq allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated irqs: %d",
+ res->irq_resource,
+ res->irq_resource
+ + (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) (sizeof(struct resource) * res->allocated_irqs)
+ + (sizeof(struct resource) * PNP_ALLOC_IRQ),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_irqs);
+ return 0;
+}
+
+static int pnp_alloc_dma(struct pnp_resource_table *res)
+{
+ int i;
+ void *ret;
+
+ ret = krealloc(res->dma_resource,
+ (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA), GFP_KERNEL);
+
+ if (!ret)
+ return -ENOMEM;
+
+ res->dma_resource = ret;
+
+ res->allocated_dmas += PNP_ALLOC_DMA;
+ for (i = res->allocated_dmas - PNP_ALLOC_DMA; i < res->allocated_dmas;
+ i++)
+ pnp_init_dma(&res->dma_resource[i]);
+
+ pnp_dbg("Dma allocate: %p - %p; Allocated: %lu bytes, size of"
+ "struct: %lu - allocated dmas: %d",
+ res->dma_resource,
+ res->dma_resource
+ + (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) (sizeof(struct resource) * res->allocated_dmas)
+ + (sizeof(struct resource) * PNP_ALLOC_DMA),
+ (unsigned long) sizeof(struct resource),
+ res->allocated_dmas);
+
+ return 0;
+}
+
+#define pnp_print_alloc_err(type, val, x) \
+ pnp_dbg("%s - cannot allocate new resource: %d in func %s " \
+ " - alloc: %d", type, val, __FUNCTION__, x)
+
+
+/*
+ * Assign a resource (IO, MEM, IRQ, DMA) to the resource table.
+ * Searches for an IORESOURCE_UNSET resource entry in the table or reallocs
+ * new resource entries as needed and copies the given resource there.
+ */
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res)
+{
+ int i = 0, ret;
+
+ if (!table || !res)
+ return -EINVAL;
+
+ if (res->flags & IORESOURCE_IO) {
+ /* find the next unused table entry */
+ while (i < table->allocated_ports) {
+ if (!(table->port_resource[i].flags
+ & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+ /* No unused table entry anymore, allocate new ones */
+ if (table->allocated_ports <= i) {
+ ret = pnp_alloc_port(table);
+ if (ret) {
+ pnp_print_alloc_err("Port", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->port_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_MEM) {
+ while (i < table->allocated_mems) {
+ if (!(table->mem_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_mems <= i) {
+ ret = pnp_alloc_mem(table);
+ if (ret) {
+ pnp_print_alloc_err("System Memory", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->mem_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_IRQ) {
+ while (i < table->allocated_irqs) {
+ if (!(table->irq_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_irqs <= i) {
+ ret = pnp_alloc_irq(table);
+ if (ret) {
+ pnp_print_alloc_err("Irq", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->irq_resource[i], res, sizeof(struct resource));
+ } else if (res->flags & IORESOURCE_DMA) {
+ while (i < table->allocated_dmas) {
+ if (!(table->dma_resource[i].flags & IORESOURCE_UNSET))
+ i++;
+ else
+ break;
+ }
+
+ if (table->allocated_dmas <= i) {
+ ret = pnp_alloc_dma(table);
+ if (ret) {
+ pnp_print_alloc_err("DMA", ret, i);
+ return ret;
+ }
+ }
+ memcpy(&table->dma_resource[i], res, sizeof(struct resource));
+ } else
+ return -EINVAL;
+
+ return 0;
+}
+
+#define pnp_print_assign_err(type, val) \
+ pnp_dbg("%s resource %d not allocated, cannot assign value", \
+ type, val);
+
+
+
+static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
+{
+ struct resource res;

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_port_valid(dev, idx) && !(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
- flags = &dev->res.port_resource[idx].flags;
+ if (pnp_port_valid(dev, idx)) {
+ /* This resource index already got some values assigned,
+ take them as init */
+ res.start = dev->res.port_resource[idx].start;
+ res.end = dev->res.port_resource[idx].end;
+ res.flags = dev->res.port_resource[idx].flags;
+ } else
+ /* This index in the table does not exist, initialize the new
+ resource and be carefuly to never access
+ dev->res.port_resource[idx] */
+ pnp_init_io(&res);

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IO;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_IO;
+ res.flags &= ~IORESOURCE_UNSET;

if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

- *start = rule->min;
- *end = *start + rule->size - 1;
+ res.start = rule->min;
+ res.end = res.start + rule->size - 1;

/* run through until pnp_check_port is happy */
while (!pnp_check_port(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
- return 0;
+ res.start += rule->align;
+ res.end = res.start + rule->size - 1;
+ if (res.start > rule->max || !rule->align)
+ return pnp_assign_resource(&dev->res, &res);
}
+ pnp_assign_resource(&dev->res, &res);
return 1;
}

static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
-
- if (idx >= PNP_MAX_MEM) {
- dev_err(&dev->dev, "too many memory resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
+ struct resource res;

/* check if this resource has been manually set, if so skip */
- if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_mem_valid(dev, idx) && !(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
- flags = &dev->res.mem_resource[idx].flags;
+ if (pnp_mem_valid(dev, idx)) {
+ res.start = dev->res.mem_resource[idx].start;
+ res.end = dev->res.mem_resource[idx].end;
+ res.flags = dev->res.mem_resource[idx].flags;
+ } else
+ pnp_init_mem(&res);

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_MEM;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_MEM;
+ res.flags &= ~IORESOURCE_UNSET;

/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
- *flags |= IORESOURCE_READONLY;
+ res.flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
- *flags |= IORESOURCE_CACHEABLE;
+ res.flags |= IORESOURCE_CACHEABLE;
if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
- *flags |= IORESOURCE_RANGELENGTH;
+ res.flags |= IORESOURCE_RANGELENGTH;
if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
- *flags |= IORESOURCE_SHADOWABLE;
+ res.flags |= IORESOURCE_SHADOWABLE;

if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

- *start = rule->min;
- *end = *start + rule->size - 1;
+ res.start = rule->min;
+ res.end = res.start + rule->size - 1;

/* run through until pnp_check_mem is happy */
while (!pnp_check_mem(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
- return 0;
+ res.start += rule->align;
+ res.end = res.start + rule->size - 1;
+ if (res.start > rule->max || !rule->align)
+ return pnp_assign_resource(&dev->res, &res);
}
+ pnp_assign_resource(&dev->res, &res);
return 1;
}

static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct resource res;
int i;

/* IRQ priority: this table is good for i386 */
@@ -119,49 +442,47 @@ static int pnp_assign_irq(struct pnp_dev
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};

- if (idx >= PNP_MAX_IRQ) {
- dev_err(&dev->dev, "too many IRQ resources\n");
- /* pretend we were successful so at least the manager won't try again */
- return 1;
- }
-
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_irq_valid(dev, idx) && !(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
return 1;

- start = &dev->res.irq_resource[idx].start;
- end = &dev->res.irq_resource[idx].end;
- flags = &dev->res.irq_resource[idx].flags;
+ if (pnp_irq_valid(dev, idx)) {
+ res.start = dev->res.irq_resource[idx].start;
+ res.end = dev->res.irq_resource[idx].end;
+ res.flags = dev->res.irq_resource[idx].flags;
+ } else
+ pnp_init_irq(&res);

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IRQ;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_IRQ;
+ res.flags &= ~IORESOURCE_UNSET;

if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
- *flags |= IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
return 1; /* skip disabled resource requests */
}

/* TBD: need check for >16 IRQ */
- *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
- if (*start < PNP_IRQ_NR) {
- *end = *start;
+ res.start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+ if (res.start < PNP_IRQ_NR) {
+ res.end = res.start;
+ pnp_assign_resource(&dev->res, &res);
return 1;
}
for (i = 0; i < 16; i++) {
if (test_bit(xtab[i], rule->map)) {
- *start = *end = xtab[i];
+ res.start = res.end = xtab[i];
if (pnp_check_irq(dev, idx))
return 1;
}
}
- return 0;
+ return pnp_assign_resource(&dev->res, &res);
}

static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct resource res;
int i;

/* DMA priority: this table is good for i386 */
@@ -169,34 +490,35 @@ static void pnp_assign_dma(struct pnp_de
1, 3, 5, 6, 7, 0, 2, 4
};

- if (idx >= PNP_MAX_DMA) {
- dev_err(&dev->dev, "too many DMA resources\n");
- return;
- }
-
/* check if this resource has been manually set, if so skip */
- if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
+ if (pnp_dma_valid(dev, idx) && !(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
return;

- start = &dev->res.dma_resource[idx].start;
- end = &dev->res.dma_resource[idx].end;
- flags = &dev->res.dma_resource[idx].flags;
+ if (pnp_dma_valid(dev, idx)) {
+ res.start = dev->res.dma_resource[idx].start;
+ res.end = dev->res.dma_resource[idx].end;
+ res.flags = dev->res.dma_resource[idx].flags;
+ } else
+ pnp_init_dma(&res);

/* set the initial values */
- *flags |= rule->flags | IORESOURCE_DMA;
- *flags &= ~IORESOURCE_UNSET;
+ res.flags |= rule->flags | IORESOURCE_DMA;
+ res.flags &= ~IORESOURCE_UNSET;

for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
- *start = *end = xtab[i];
- if (pnp_check_dma(dev, idx))
+ res.start = res.end = xtab[i];
+ if (pnp_check_dma(dev, idx)){
+ pnp_assign_resource(&dev->res, &res);
return;
+ }
}
}
#ifdef MAX_DMA_CHANNELS
- *start = *end = MAX_DMA_CHANNELS;
+ res.start = res.end = MAX_DMA_CHANNELS;
#endif
- *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ res.flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ pnp_assign_resource(&dev->res, &res);
}

/**
@@ -207,28 +529,28 @@ void pnp_init_resource_table(struct pnp_
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < table->allocated_irqs; idx++) {
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < table->allocated_dmas; idx++) {
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < table->allocated_ports; idx++) {
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < table->allocated_mems; idx++) {
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0;
@@ -245,7 +567,7 @@ static void pnp_clean_resource_table(str
{
int idx;

- for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
+ for (idx = 0; idx < res->allocated_irqs; idx++) {
if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->irq_resource[idx].start = -1;
@@ -253,7 +575,7 @@ static void pnp_clean_resource_table(str
res->irq_resource[idx].flags =
IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_DMA; idx++) {
+ for (idx = 0; idx < res->allocated_dmas; idx++) {
if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->dma_resource[idx].start = -1;
@@ -261,7 +583,7 @@ static void pnp_clean_resource_table(str
res->dma_resource[idx].flags =
IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_PORT; idx++) {
+ for (idx = 0; idx < res->allocated_ports; idx++) {
if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->port_resource[idx].start = 0;
@@ -269,7 +591,7 @@ static void pnp_clean_resource_table(str
res->port_resource[idx].flags =
IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
}
- for (idx = 0; idx < PNP_MAX_MEM; idx++) {
+ for (idx = 0; idx < res->allocated_mems; idx++) {
if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
continue;
res->mem_resource[idx].start = 0;
@@ -386,46 +708,12 @@ fail:
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
int mode)
{
- int i;
- struct pnp_resource_table *bak;
-
- if (!pnp_can_configure(dev))
- return -ENODEV;
- bak = pnp_alloc(sizeof(struct pnp_resource_table));
- if (!bak)
- return -ENOMEM;
- *bak = dev->res;
-
- down(&pnp_res_mutex);
- dev->res = *res;
- if (!(mode & PNP_CONFIG_FORCE)) {
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_check_port(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_check_mem(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (!pnp_check_irq(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (!pnp_check_dma(dev, i))
- goto fail;
- }
- }
- up(&pnp_res_mutex);
-
- kfree(bak);
- return 0;
+ /* We must never end up here, these functions are poisson for dynamic
+ allocation via pointer array.
+ */
+ BUG_ON(1);
+ return 1;

-fail:
- dev->res = *bak;
- up(&pnp_res_mutex);
- kfree(bak);
- return -EINVAL;
}

/**
@@ -563,6 +851,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
void pnp_resource_change(struct resource *resource, resource_size_t start,
resource_size_t size)
{
+ return;
resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
resource->start = start;
resource->end = start + size - 1;
Index: linux-acpi-2.6/drivers/pnp/pnpacpi/rsparser.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/pnpacpi/rsparser.c
+++ linux-acpi-2.6/drivers/pnp/pnpacpi/rsparser.c
@@ -73,23 +73,16 @@ static void pnpacpi_parse_allocated_irqr
u32 gsi, int triggering,
int polarity, int shareable)
{
- int i = 0;
int irq;
int p, t;
- static unsigned char warned;
+
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };

if (!valid_IRQ(gsi))
return;

- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
- i++;
- if (i >= PNP_MAX_IRQ && !warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ "
- "resources: %d \n", PNP_MAX_IRQ);
- warned = 1;
- return;
- }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
@@ -107,20 +100,26 @@ static void pnpacpi_parse_allocated_irqr
}
}

- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- res->irq_resource[i].flags |= irq_flags(triggering, polarity);
+ new_res.flags |= irq_flags(triggering, polarity);
irq = acpi_register_gsi(gsi, triggering, polarity);
if (irq < 0) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
return;
}

if (shareable)
- res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
+ new_res.flags |= IORESOURCE_IRQ_SHAREABLE;

- res->irq_resource[i].start = irq;
- res->irq_resource[i].end = irq;
+ new_res.start = irq;
+ new_res.end = irq;
pcibios_penalize_isa_irq(irq, 1);
+
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static int dma_flags(int type, int bus_master, int transfer)
@@ -170,81 +169,71 @@ static void pnpacpi_parse_allocated_dmar
u32 dma, int type,
int bus_master, int transfer)
{
- int i = 0;
- static unsigned char warned;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- res->dma_resource[i].flags |=
- dma_flags(type, bus_master, transfer);
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start = dma;
- res->dma_resource[i].end = dma;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of DMA "
- "resources: %d \n", PNP_MAX_DMA);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ new_res.flags |= dma_flags(type, bus_master, transfer);
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = dma;
+ new_res.end = dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
u64 io, u64 len, int io_decode)
{
- int i = 0;
- static unsigned char warned;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (io_decode == ACPI_DECODE_16)
- res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = io;
- res->port_resource[i].end = io + len - 1;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of IO "
- "resources: %d \n", PNP_MAX_PORT);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (io_decode == ACPI_DECODE_16)
+ new_res.flags |= PNP_PORT_FLAG_16BITADDR;
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ new_res.start = io;
+ new_res.end = io + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
u64 mem, u64 len,
int write_protect)
{
- int i = 0;
- static unsigned char warned;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
-
- res->mem_resource[i].start = mem;
- res->mem_resource[i].end = mem + len - 1;
- } else if (!warned) {
- printk(KERN_ERR "pnpacpi: exceeded the max number of mem "
- "resources: %d\n", PNP_MAX_MEM);
- warned = 1;
- }
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
+ }
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ new_res.flags |= IORESOURCE_MEM_WRITEABLE;
+
+ new_res.start = mem;
+ new_res.end = mem + len - 1;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
Index: linux-acpi-2.6/drivers/pnp/pnpbios/rsparser.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/pnpbios/rsparser.c
+++ linux-acpi-2.6/drivers/pnp/pnpbios/rsparser.c
@@ -56,78 +56,84 @@ inline void pcibios_penalize_isa_irq(int
static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
int irq)
{
- int i = 0;
-
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_IRQ)
- i++;
- if (i < PNP_MAX_IRQ) {
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- if (irq == -1) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->irq_resource[i].start =
- res->irq_resource[i].end = (unsigned long)irq;
- pcibios_penalize_isa_irq(irq, 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IRQ,
+ };
+
+ if (irq == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)irq;
+ pcibios_penalize_isa_irq(irq, 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
int dma)
{
- int i = 0;
-
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start =
- res->dma_resource[i].end = (unsigned long)dma;
+ struct resource new_res = {
+ .flags = IORESOURCE_DMA,
+ };
+
+ if (dma == -1) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = new_res.end = (unsigned long)dma;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
int io, int len)
{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = (unsigned long)io;
- res->port_resource[i].end = (unsigned long)(io + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_IO,
+ };
+
+ if (len <= 0 || (io + len - 1) >= 0x10003) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)io;
+ new_res.end = (unsigned long)(io + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
int mem, int len)
{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_MEM)
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->mem_resource[i].start = (unsigned long)mem;
- res->mem_resource[i].end = (unsigned long)(mem + len - 1);
+ struct resource new_res = {
+ .flags = IORESOURCE_MEM,
+ };
+
+ if (len <= 0) {
+ /* <trenn> Check: Do we need to allocate and assign
+ this resource at all? */
+ new_res.flags |= IORESOURCE_DISABLED;
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
+ return;
}
+ new_res.start = (unsigned long)mem;
+ new_res.end = (unsigned long)(mem + len - 1);
+ if (pnp_assign_resource(res, &new_res))
+ pnp_err("Bug in %s", __FUNCTION__);
}

static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
Index: linux-acpi-2.6/drivers/pnp/resource.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/resource.c
+++ linux-acpi-2.6/drivers/pnp/resource.c
@@ -242,7 +242,7 @@ int pnp_check_port(struct pnp_dev *dev,
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_port_valid(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
@@ -255,7 +255,7 @@ int pnp_check_port(struct pnp_dev *dev,
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
+ for (tmp = 0; pnp_port_valid(tdev, tmp); tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
if (cannot_compare
(tdev->res.port_resource[tmp].flags))
@@ -300,7 +300,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_mem_valid(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
@@ -313,7 +313,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
+ for (tmp = 0; pnp_mem_valid(tdev, tmp); tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
if (cannot_compare
(tdev->res.mem_resource[tmp].flags))
@@ -355,7 +355,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_irq_valid(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (dev->res.irq_resource[tmp].start == *irq)
return 0;
@@ -388,7 +388,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
+ for (tmp = 0; pnp_irq_valid(tdev, tmp); tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (cannot_compare
(tdev->res.irq_resource[tmp].flags))
@@ -424,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
}

/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
+ for (tmp = 0; pnp_dma_valid(dev, tmp) && tmp != idx; tmp++) {
if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return 0;
@@ -443,7 +443,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
+ for (tmp = 0; pnp_dma_valid(tdev, tmp); tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (cannot_compare
(tdev->res.dma_resource[tmp].flags))
Index: linux-acpi-2.6/drivers/pnp/support.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/support.c
+++ linux-acpi-2.6/drivers/pnp/support.c
@@ -14,11 +14,16 @@
* resources
* @dev: pointer to the desired PnP device
*/
+
+/* <trenn> This interface is only used by pnpbios and one driver:
+ sound/isa/sscape.c
+ drivers can check for pnp_port_valid... anyway
+ This one is not needed.
+*/
int pnp_is_active(struct pnp_dev *dev)
{
- if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
- !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
- pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
+ if (dev->res.allocated_ports <= 0 && dev->res.allocated_mems <= 0 &&
+ dev->res.allocated_irqs <= 0 && dev->res.allocated_dmas <= 0)
return 0;
else
return 1;
Index: linux-acpi-2.6/drivers/pnp/system.c
===================================================================
--- linux-acpi-2.6.orig/drivers/pnp/system.c
+++ linux-acpi-2.6/drivers/pnp/system.c
@@ -58,7 +58,7 @@ static void reserve_resources_of_dev(str
{
int i;

- for (i = 0; i < PNP_MAX_PORT; i++) {
+ for (i = 0; pnp_port_valid(dev, i); i++) {
if (!pnp_port_valid(dev, i))
continue;
if (pnp_port_start(dev, i) == 0)
@@ -80,7 +80,7 @@ static void reserve_resources_of_dev(str
pnp_port_end(dev, i), 1);
}

- for (i = 0; i < PNP_MAX_MEM; i++) {
+ for (i = 0; pnp_mem_valid(dev, i); i++) {
if (!pnp_mem_valid(dev, i))
continue;

Index: linux-acpi-2.6/include/linux/pnp.h
===================================================================
--- linux-acpi-2.6.orig/include/linux/pnp.h
+++ linux-acpi-2.6/include/linux/pnp.h
@@ -13,10 +13,6 @@
#include <linux/errno.h>
#include <linux/mod_devicetable.h>

-#define PNP_MAX_PORT 40
-#define PNP_MAX_MEM 12
-#define PNP_MAX_IRQ 2
-#define PNP_MAX_DMA 2
#define PNP_NAME_LEN 50

struct pnp_protocol;
@@ -26,12 +22,24 @@ struct pnp_dev;
* Resource Management
*/

-/* Use these instead of directly reading pnp_dev to get resource information */
-#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
-#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
-#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
-#define pnp_port_valid(dev,bar) \
- ((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
+/*
+ * NULL pointer alarm: always check with pnp_port_valid or pnp_port_valid before
+ * accessing start/end/flags/len values or you might access not allocated mem.
+ * Same for mem, irq and dma macros
+ *
+ * Pointers are not static and they might change, do not store addresses
+ * of resources in the pnp resource table!
+ */
+
+#define pnp_port_start(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].start \
+ : pnp_dbg("WARN: Port start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_end(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].end \
+ : pnp_dbg("WARN: Port end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_flags(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].flags \
+ : pnp_dbg("WARN: Port flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_port_valid(dev,bar) \
+ (((dev)->res.allocated_ports > (bar)) && \
+ (((dev)->res.port_resource[(bar)].flags) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
== IORESOURCE_IO)
#define pnp_port_len(dev,bar) \
((pnp_port_start((dev),(bar)) == 0 && \
@@ -41,11 +49,15 @@ struct pnp_dev;
(pnp_port_end((dev),(bar)) - \
pnp_port_start((dev),(bar)) + 1))

-#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
-#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
-#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
+#define pnp_mem_start(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].start \
+ : pnp_dbg("Mem start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_mem_end(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].end \
+ : pnp_dbg("Mem end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_mem_flags(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].flags \
+ : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_mem_valid(dev,bar) \
- ((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
+ (((dev)->res.allocated_mems > (bar)) && \
+ (((dev)->res.mem_resource[(bar)].flags) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
== IORESOURCE_MEM)
#define pnp_mem_len(dev,bar) \
((pnp_mem_start((dev),(bar)) == 0 && \
@@ -55,16 +67,22 @@ struct pnp_dev;
(pnp_mem_end((dev),(bar)) - \
pnp_mem_start((dev),(bar)) + 1))

-#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
-#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
+#define pnp_irq(dev,bar) (pnp_irq_valid((dev),(bar)) ? (dev)->res.irq_resource[(bar)].start \
+ : pnp_dbg("Irq start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_irq_flags(dev,bar) (pnp_irq_valid((dev),(bar)) ? (dev)->res.irq_resource[(bar)].flags \
+ : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_irq_valid(dev,bar) \
- ((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
+ (((dev)->res.allocated_irqs > (bar)) && \
+ (((dev)->res.irq_resource[(bar)].flags) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
== IORESOURCE_IRQ)

-#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
-#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
+#define pnp_dma(dev,bar) (pnp_dma_valid((dev),(bar)) ? (dev)->res.dma_resource[(bar)].start \
+ : pnp_dbg("Dma start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
+#define pnp_dma_flags(dev,bar) (pnp_dma_valid((dev),(bar)) ? (dev)->res.dma_resource[(bar)].flags \
+ : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
#define pnp_dma_valid(dev,bar) \
- ((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
+ (((dev)->res.allocated_dmas > (bar)) && \
+ (((dev)->res.dma_resource[(bar)].flags) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
== IORESOURCE_DMA)

#define PNP_PORT_FLAG_16BITADDR (1<<0)
@@ -119,10 +137,14 @@ struct pnp_option {
};

struct pnp_resource_table {
- struct resource port_resource[PNP_MAX_PORT];
- struct resource mem_resource[PNP_MAX_MEM];
- struct resource dma_resource[PNP_MAX_DMA];
- struct resource irq_resource[PNP_MAX_IRQ];
+ struct resource *port_resource;
+ unsigned int allocated_ports;
+ struct resource *mem_resource;
+ unsigned int allocated_mems;
+ struct resource *dma_resource;
+ unsigned int allocated_dmas;
+ struct resource *irq_resource;
+ unsigned int allocated_irqs;
};

/*
@@ -364,6 +386,7 @@ int pnp_device_attach(struct pnp_dev *pn
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
extern int pnp_platform_devices;
+extern int pnp_bios_data_parsed;

/* multidevice card support */
int pnp_add_card(struct pnp_card *card);
@@ -398,6 +421,8 @@ int pnp_activate_dev(struct pnp_dev *dev
int pnp_disable_dev(struct pnp_dev *dev);
void pnp_resource_change(struct resource *resource, resource_size_t start,
resource_size_t size);
+int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res);
+

/* protocol helpers */
int pnp_is_active(struct pnp_dev *dev);
@@ -445,6 +470,7 @@ static inline int pnp_stop_dev(struct pn
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { }
+static inline int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res) { }

/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
@@ -460,9 +486,11 @@ static inline void pnp_unregister_driver
#define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)

#ifdef CONFIG_PNP_DEBUG
-#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
+#define pnp_dbg(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
+void pnp_dump_resources(struct pnp_dev *dev);
#else
#define pnp_dbg(format, arg...) do {} while (0)
+static inline void pnp_dump_resources(struct pnp_dev *dev) { }
#endif

#endif /* __KERNEL__ */

2008-02-06 14:39:04

by Thomas Renninger

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - Yet another Version

On Tue, 2008-02-05 at 19:20 +0100, Thomas Renninger wrote:
> On Mon, 2008-01-28 at 22:12 +0100, Rene Herman wrote:
> > On 28-01-08 20:12, Thomas Renninger wrote:
> >
> > > This was more a step backward, hopefully this one (on top), gets the
> > > area bugfree?
>
> This one includes findings from tests with Rene on a isa system.
> It handles possible NULL pointers and checks them inside the
> pnp_{mem,dma,irq,port}_{start,end,flags}. Which is a must for now with
> dynamic allocated resources. I first thought this could be checked
> inside the drivers with pnp_*_valid, but for now this is safer and
> easier to do.
>
> I also integrated a suggestion from Bjorn and eliminated the not needed
> pnp_*_ok macros and used pnp_*_valid instead.
> Testcompiled with one example .config. I still build with different
> configs, I will let you know if anything did not build tomorrow (if not
> it builds).

Arg, it does not build when PNP_CONFIG is not set (and it is broken...).
The problem is (include/linux/pnp.h):
#define pnp_port_start(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].start \
: pnp_dbg("WARN: Port start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))

If PNP_CONFIG is not set, pnp_dbg is:
#define pnp_dbg(format, arg...) do {} while (0)

Not sure how this could be implemented in the nicest way.
Having at least a debug warning here should be added because it could
point to BIOS bugs.
E.g. (what I expect also happens on Rene's machine), drivers are
checking for port, mem, irq, dma resources they need. Without dynamic
allocation they could just access the array and check whether there are
unused/unfilled resources (they now also can with this patch (if done
correctly..) with the pnp_port_valid inside the pnp_port_start macro).

I expect on Rene's machine (might be something else, but this probably
often happens), BIOS exports dma and IO ports. The irq seem to be
missing and the driver does not use pnp_irq_valid, but pnp_irq. It
realizes it has no sane or an uninitialized value and makes up and uses
an irq which the driver thinks is best.
So having a message when a driver is trying to access a resource which
it seem to expect from BIOS, but has not been exported is a thing we
want to have, at least in PNP_DEBUG case.
Best would be to fix up all drivers..., but IMO this should at least be
split up in two steps and this check and the message in the pnp layer
should be added anyway.

Here an idea (thanks for hints go to Bernhard Walle), but it's still not
perfect (pnp.h would get quite big with it...), maybe someone has a
better idea:

static inline int pnp_port_start_f(dev, bar, fun, line)
{
if (pnp_port_valid(dev,bar))
return (dev)->res.port_resource[(bar)].start;
else {
pnp_dbg("WARN: Port end %d - [%s] invalid - %s:%d", (bar), (dev->name), fun, line);
return 0;
}
}
#define pnp_port_start(dev,bar) pnp_port_f(start, dev, bar, __FUNCTION__, __LINE__)

Like that, one would get a hint which drivers (in which func and line)
tries to access a resource which it seem to expect gets exported by
BIOS, but did not.

I wait now for some response/ideas before polluting the list even
more...

Thomas

> ------------
>
> Allocate pnp resources dynamically via krealloc
>
> Latest BIOS ACPI PNP device resource descriptions may have (especially on the
> general device PNP0c02) more than 20 IO port resources.
> Reserve the space in a static array wastes a lot of memory on every PNP device
> and is not a real option as the number of IO ports could be much greater than
> 20.
>
> This approach allocates the memory for PNP resources at runtime.
> The memory is reallocated in e.g. 8 (for IO port) resource portions.
> That means that the previously allocated pointers will get a new address.
> Therefore this address must not be stored and/or used as long as krealloc
> might still allocate new resources.
> >From what I have seen, there is a patch in -mm that gets rid of
> registering resources automatically and pass the pointers from
> pnp_resource_table to request_region.
> While this should still work (only disabled devices where the regions
> should have been unregistered should be modifyable) it is potential
> dangereous: once you realloc pnp_resource_table pointers you end up
> with invalid pointers in the kernel/resource.c implemented list.
> Finding this could get difficult as you get really ugly phenomenons with
> corrupted memory...
>
>
> The patch also needs another patch from Rene Herman:
> "[PATCH] sound/isa: kill pnp_resource_change."
> Sent to the alsa-devel list and it's already included in Takashi's tree
> for 2.6.25 inclusion.
> The function pnp_resource_change is a nop now and immediately returns to avoid
> compile errors. It can be removed as soon as everything is merged together.
>
> This has been tested on rather new machines on i386 and x86_64.
> The first with pnpbios also compiled in and forced a test with pnpacpi=off.
>
> isapnp was partly tested by Rene. Whether this latest version works there
> still needs a test.
> Also the sysfs interface is rather untested.
>
> I tried to play a bit with the sysfs interface and wanted override
> resources without much success:
> Unloaded parport_pc driver, then the corresponding pnp device changed state
> from active to disabled and now I should have been able to modify BIOS
> settings, but it did not work. I expect this is rather unused and could have
> been broken before and I did not want to loose more time with it.
> Maybe someone else knows more here.
>
>
> ---
> drivers/pnp/core.c | 2
> drivers/pnp/interface.c | 44 ++-
> drivers/pnp/isapnp/core.c | 58 +++-
> drivers/pnp/manager.c | 549 +++++++++++++++++++++++++++++++----------
> drivers/pnp/pnpacpi/rsparser.c | 151 +++++------
> drivers/pnp/pnpbios/rsparser.c | 112 ++++----
> drivers/pnp/resource.c | 16 -
> drivers/pnp/support.c | 11
> drivers/pnp/system.c | 4
> include/linux/pnp.h | 78 +++--
> 10 files changed, 694 insertions(+), 331 deletions(-)
>
> Index: linux-acpi-2.6/drivers/pnp/core.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/core.c
> +++ linux-acpi-2.6/drivers/pnp/core.c
> @@ -129,6 +129,7 @@ int __pnp_add_device(struct pnp_dev *dev
> return ret;
>
> pnp_interface_attach_device(dev);
> + pnp_dump_resources(dev);
> return 0;
> }
>
> @@ -148,6 +149,7 @@ int pnp_add_device(struct pnp_dev *dev)
> dev->dev.parent = &dev->protocol->dev;
> sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
> dev->number);
> + pnp_dbg("Adding device %s - %s", dev->name, dev->dev.bus_id);
> ret = __pnp_add_device(dev);
> if (ret)
> return ret;
> Index: linux-acpi-2.6/drivers/pnp/interface.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/interface.c
> +++ linux-acpi-2.6/drivers/pnp/interface.c
> @@ -264,7 +264,7 @@ static ssize_t pnp_show_current_resource
> else
> pnp_printf(buffer, "disabled\n");
>
> - for (i = 0; i < PNP_MAX_PORT; i++) {
> + for (i = 0; pnp_port_valid(dev, i); i++) {
> if (pnp_port_valid(dev, i)) {
> pnp_printf(buffer, "io");
> if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
> @@ -277,7 +277,7 @@ static ssize_t pnp_show_current_resource
> i));
> }
> }
> - for (i = 0; i < PNP_MAX_MEM; i++) {
> + for (i = 0; pnp_mem_valid(dev, i); i++) {
> if (pnp_mem_valid(dev, i)) {
> pnp_printf(buffer, "mem");
> if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
> @@ -290,7 +290,7 @@ static ssize_t pnp_show_current_resource
> i));
> }
> }
> - for (i = 0; i < PNP_MAX_IRQ; i++) {
> + for (i = 0; pnp_irq_valid(dev, i); i++) {
> if (pnp_irq_valid(dev, i)) {
> pnp_printf(buffer, "irq");
> if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
> @@ -300,7 +300,7 @@ static ssize_t pnp_show_current_resource
> (unsigned long long)pnp_irq(dev, i));
> }
> }
> - for (i = 0; i < PNP_MAX_DMA; i++) {
> + for (i = 0; pnp_dma_valid(dev, i); i++) {
> if (pnp_dma_valid(dev, i)) {
> pnp_printf(buffer, "dma");
> if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
> @@ -381,6 +381,13 @@ pnp_set_current_resources(struct device
> buf += 2;
> while (isspace(*buf))
> ++buf;
> + if (!pnp_port_valid(dev, nport)) {
> + buf++;
> + pnp_err("Cannot manually set port"
> + "resource %d for device %s",
> + nport, dev->name);
> + continue;
> + }
> dev->res.port_resource[nport].start =
> simple_strtoul(buf, &buf, 0);
> while (isspace(*buf))
> @@ -397,14 +404,19 @@ pnp_set_current_resources(struct device
> dev->res.port_resource[nport].flags =
> IORESOURCE_IO;
> nport++;
> - if (nport >= PNP_MAX_PORT)
> - break;
> continue;
> }
> if (!strnicmp(buf, "mem", 3)) {
> buf += 3;
> while (isspace(*buf))
> ++buf;
> + if (!pnp_mem_valid(dev, nmem)) {
> + buf++;
> + pnp_err("Cannot manually set mem "
> + "resource %d for device %s",
> + nmem, dev->name);
> + continue;
> + }
> dev->res.mem_resource[nmem].start =
> simple_strtoul(buf, &buf, 0);
> while (isspace(*buf))
> @@ -421,36 +433,44 @@ pnp_set_current_resources(struct device
> dev->res.mem_resource[nmem].flags =
> IORESOURCE_MEM;
> nmem++;
> - if (nmem >= PNP_MAX_MEM)
> - break;
> continue;
> }
> if (!strnicmp(buf, "irq", 3)) {
> buf += 3;
> while (isspace(*buf))
> ++buf;
> + if (!pnp_irq_valid(dev, nirq)) {
> + buf++;
> + pnp_err("Cannot manually set irq "
> + "resource %d for device %s",
> + nirq, dev->name);
> + continue;
> + }
> dev->res.irq_resource[nirq].start =
> dev->res.irq_resource[nirq].end =
> simple_strtoul(buf, &buf, 0);
> dev->res.irq_resource[nirq].flags =
> IORESOURCE_IRQ;
> nirq++;
> - if (nirq >= PNP_MAX_IRQ)
> - break;
> continue;
> }
> if (!strnicmp(buf, "dma", 3)) {
> buf += 3;
> while (isspace(*buf))
> ++buf;
> + if (!pnp_dma_valid(dev, ndma)) {
> + buf++;
> + pnp_err("Cannot manually set dma "
> + "resource %d for device %s",
> + ndma, dev->name);
> + continue;
> + }
> dev->res.dma_resource[ndma].start =
> dev->res.dma_resource[ndma].end =
> simple_strtoul(buf, &buf, 0);
> dev->res.dma_resource[ndma].flags =
> IORESOURCE_DMA;
> ndma++;
> - if (ndma >= PNP_MAX_DMA)
> - break;
> continue;
> }
> break;
> Index: linux-acpi-2.6/drivers/pnp/isapnp/core.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/isapnp/core.c
> +++ linux-acpi-2.6/drivers/pnp/isapnp/core.c
> @@ -42,6 +42,7 @@
> #include <linux/init.h>
> #include <linux/isapnp.h>
> #include <linux/mutex.h>
> +
> #include <asm/io.h>
>
> #if 0
> @@ -65,6 +66,12 @@ module_param(isapnp_verbose, int, 0);
> MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
> MODULE_LICENSE("GPL");
>
> +/* ISAPNP is restricted to these limits by spec */
> +#define PNP_MAX_PORT 8
> +#define PNP_MAX_MEM 4
> +#define PNP_MAX_IRQ 2
> +#define PNP_MAX_DMA 2
> +
> #define _PIDXR 0x279
> #define _PNPWRP 0xa79
>
> @@ -942,41 +949,58 @@ static int isapnp_read_resources(struct
> struct pnp_resource_table *res)
> {
> int tmp, ret;
> + struct resource new_res;
>
> dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
> if (dev->active) {
> - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
> + for (tmp = 0; pnp_port_valid(dev, tmp); tmp++) {
> ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
> if (!ret)
> continue;
> - res->port_resource[tmp].start = ret;
> - res->port_resource[tmp].flags = IORESOURCE_IO;
> + new_res.start = ret;
> + new_res.flags = IORESOURCE_IO;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + if (tmp > PNP_MAX_PORT)
> + pnp_warn("ISA exceeds spec max port");
> }
> - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
> + for (tmp = 0; pnp_mem_valid(dev, tmp); tmp++) {
> ret =
> isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
> if (!ret)
> continue;
> - res->mem_resource[tmp].start = ret;
> - res->mem_resource[tmp].flags = IORESOURCE_MEM;
> + new_res.start = ret;
> + new_res.flags = IORESOURCE_MEM;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + if (tmp > PNP_MAX_MEM)
> + pnp_warn("ISA exceeds spec max mem");
> }
> - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
> + for (tmp = 0; pnp_irq_valid(dev, tmp); tmp++) {
> ret =
> (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
> 8);
> if (!ret)
> continue;
> - res->irq_resource[tmp].start =
> - res->irq_resource[tmp].end = ret;
> - res->irq_resource[tmp].flags = IORESOURCE_IRQ;
> + new_res.start = new_res.end = ret;
> + new_res.flags = IORESOURCE_IRQ;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + if (tmp > PNP_MAX_IRQ)
> + pnp_warn("ISA exceeds spec max irq");
> +
> }
> - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
> + for (tmp = 0; pnp_dma_valid(dev, tmp); tmp++) {
> ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
> if (ret == 4)
> continue;
> res->dma_resource[tmp].start =
> - res->dma_resource[tmp].end = ret;
> - res->dma_resource[tmp].flags = IORESOURCE_DMA;
> + new_res.start = new_res.end = ret;
> + new_res.flags = IORESOURCE_DMA;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + if (tmp > PNP_MAX_DMA)
> + pnp_warn("ISA exceeds spec max dma");
> }
> }
> return 0;
> @@ -1002,14 +1026,14 @@ static int isapnp_set_resources(struct p
> isapnp_cfg_begin(dev->card->number, dev->number);
> dev->active = 1;
> for (tmp = 0;
> - tmp < PNP_MAX_PORT
> + pnp_port_valid(dev, tmp)
> && (res->port_resource[tmp].
> flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
> tmp++)
> isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
> res->port_resource[tmp].start);
> for (tmp = 0;
> - tmp < PNP_MAX_IRQ
> + pnp_irq_valid(dev, tmp)
> && (res->irq_resource[tmp].
> flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
> tmp++) {
> @@ -1019,14 +1043,14 @@ static int isapnp_set_resources(struct p
> isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
> }
> for (tmp = 0;
> - tmp < PNP_MAX_DMA
> + pnp_dma_valid(dev, tmp)
> && (res->dma_resource[tmp].
> flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
> tmp++)
> isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
> res->dma_resource[tmp].start);
> for (tmp = 0;
> - tmp < PNP_MAX_MEM
> + pnp_mem_valid(dev, tmp)
> && (res->mem_resource[tmp].
> flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
> tmp++)
> Index: linux-acpi-2.6/drivers/pnp/manager.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/manager.c
> +++ linux-acpi-2.6/drivers/pnp/manager.c
> @@ -14,104 +14,427 @@
> #include <linux/bitmap.h>
> #include "base.h"
>
> +/* Defines the amount of struct resources that will get (re-)alloced
> + * if the resource table runs out of allocated ports/irqs/dma/mems
> + */
> +#define PNP_ALLOC_PORT 8
> +#define PNP_ALLOC_MEM 4
> +#define PNP_ALLOC_IRQ 2
> +#define PNP_ALLOC_DMA 2
> +
> DECLARE_MUTEX(pnp_res_mutex);
>
> -static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
> +#ifdef CONFIG_PNP_DEBUG
> +void pnp_dump_resources(struct pnp_dev *dev)
> {
> - resource_size_t *start, *end;
> - unsigned long *flags;
> -
> - if (idx >= PNP_MAX_PORT) {
> - dev_err(&dev->dev, "too many I/O port resources\n");
> - /* pretend we were successful so at least the manager won't try again */
> - return 1;
> + int i;
> + pnp_dbg("Resource table dump:");
> + pnp_dbg("Allocted: ports: %d [%p - %p]",
> + dev->res.allocated_ports, dev->res.port_resource,
> + dev->res.port_resource + (dev->res.allocated_ports *
> + sizeof(struct resource)));
> + for (i = 0; pnp_port_valid(dev, i); i++) {
> + pnp_dbg("Port %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
> + (unsigned long)pnp_port_start(dev, i),
> + (unsigned long)pnp_port_end(dev, i),
> + pnp_port_flags(dev, i));
> + }
> + pnp_dbg("Allocted: mems: %d [%p - %p]",
> + dev->res.allocated_mems, dev->res.mem_resource,
> + dev->res.mem_resource + (dev->res.allocated_mems *
> + sizeof(struct resource)));
> + for (i = 0; pnp_mem_valid(dev, i); i++) {
> + pnp_dbg("Mem %d: start: 0x%lx - end: 0x%lx - flags: %lu", i,
> + (unsigned long)pnp_mem_start(dev, i),
> + (unsigned long)pnp_mem_end(dev, i),
> + pnp_mem_flags(dev, i));
> + }
> + pnp_dbg("Allocted: irqs: %d [%p - %p]",
> + dev->res.allocated_irqs, dev->res.irq_resource,
> + dev->res.irq_resource + (dev->res.allocated_irqs *
> + sizeof(struct resource)));
> + for (i = 0; pnp_irq_valid(dev, i); i++) {
> + pnp_dbg("Irq %d: start: 0x%lx - flags: %lu", i,
> + (unsigned long)pnp_irq(dev, i),
> + pnp_irq_flags(dev, i));
> + }
> + pnp_dbg("Allocted: dmas: %d [%p - %p]",
> + dev->res.allocated_dmas, dev->res.dma_resource,
> + dev->res.dma_resource + (dev->res.allocated_dmas *
> + sizeof(struct resource)));
> + for (i = 0; pnp_dma_valid(dev, i); i++) {
> + pnp_dbg("Dma %d: start: 0x%lx - flags: %lu", i,
> + (unsigned long)pnp_dma(dev, i),
> + pnp_dma_flags(dev, i));
> }
> +}
> +#endif
> +
> +static void pnp_init_io(struct resource *res)
> +{
> + res->name = NULL;
> + res->start = 0;
> + res->end = 0;
> + res->flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
> +}
> +static void pnp_init_mem(struct resource *res)
> +{
> + res->name = NULL;
> + res->start = 0;
> + res->end = 0;
> + res->flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
> +}
> +static void pnp_init_irq(struct resource *res)
> +{
> + res->name = NULL;
> + res->start = -1;
> + res->end = -1;
> + res->flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
> +}
> +static void pnp_init_dma(struct resource *res)
> +{
> + res->name = NULL;
> + res->start = -1;
> + res->end = -1;
> + res->flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
> +}
> +
> +/****************************************************************
> + *
> + * pnp_alloc_{port,dma,irq,mem}
> + *
> + * These functions must only be when a device is not active and
> + * can therefore not have any resources requested via kernel/resource.c
> + * If the pnp resource table has not enough (or none) resources of
> + * a specific type allocated, the memory of the array is increased
> + * via krealloc, which results in changed pointers of all already
> + * allocated struct resources in the table.
> + * This would invalidate the addresses passed to request/insert_resource
> + */
> +
> +static int pnp_alloc_port(struct pnp_resource_table *res)
> +{
> + int i;
> + void *ret;
> +
> + ret = krealloc(res->port_resource,
> + (sizeof(struct resource) * res->allocated_ports)
> + + (sizeof(struct resource) * PNP_ALLOC_PORT), GFP_KERNEL);
> +
> + if (!ret)
> + return -ENOMEM;
> +
> + res->port_resource = ret;
> +
> + res->allocated_ports += PNP_ALLOC_PORT;
> + for (i = res->allocated_ports - PNP_ALLOC_PORT;
> + i < res->allocated_ports; i++)
> + pnp_init_io(&res->port_resource[i]);
> +
> + pnp_dbg("Port allocate: %p - %p; Allocated: %lu bytes, size of"
> + "struct: %lu - allocated ports: %d",
> + res->port_resource,
> + res->port_resource
> + + (sizeof(struct resource) * res->allocated_ports)
> + + (sizeof(struct resource) * PNP_ALLOC_PORT),
> + (unsigned long) (sizeof(struct resource) * res->allocated_ports)
> + + (sizeof(struct resource) * PNP_ALLOC_PORT),
> + (unsigned long) sizeof(struct resource),
> + res->allocated_ports);
> +
> + return 0;
> +}
> +
> +static int pnp_alloc_mem(struct pnp_resource_table *res)
> +{
> + int i;
> + void *ret;
> +
> + ret = krealloc(res->mem_resource,
> + (sizeof(struct resource) * res->allocated_mems)
> + + (sizeof(struct resource) * PNP_ALLOC_MEM), GFP_KERNEL);
> +
> + if (!ret)
> + return -ENOMEM;
> +
> + res->mem_resource = ret;
> +
> + res->allocated_mems += PNP_ALLOC_MEM;
> +
> + for (i = res->allocated_mems - PNP_ALLOC_MEM; i < res->allocated_mems;
> + i++)
> + pnp_init_mem(&res->mem_resource[i]);
> +
> + pnp_dbg("Mem allocate: %p - %p; Allocated: %lu bytes, size of"
> + "struct: %lu - allocated mems: %d",
> + res->mem_resource,
> + res->mem_resource
> + + (sizeof(struct resource) * res->allocated_mems)
> + + (sizeof(struct resource) * PNP_ALLOC_MEM),
> + (unsigned long) (sizeof(struct resource) * res->allocated_mems)
> + + (sizeof(struct resource) * PNP_ALLOC_MEM),
> + (unsigned long) sizeof(struct resource),
> + res->allocated_mems);
> +
> + return 0;
> +}
> +
> +static int pnp_alloc_irq(struct pnp_resource_table *res)
> +{
> + int i;
> + void *ret;
> +
> + ret = krealloc(res->irq_resource,
> + (sizeof(struct resource) * res->allocated_irqs)
> + + (sizeof(struct resource) * PNP_ALLOC_IRQ), GFP_KERNEL);
> +
> + if (!ret)
> + return -ENOMEM;
> +
> + res->irq_resource = ret;
> +
> + res->allocated_irqs += PNP_ALLOC_IRQ;
> + for (i = res->allocated_irqs - PNP_ALLOC_IRQ; i < res->allocated_irqs;
> + i++)
> + pnp_init_irq(&res->irq_resource[i]);
> +
> + pnp_dbg("Irq allocate: %p - %p; Allocated: %lu bytes, size of"
> + "struct: %lu - allocated irqs: %d",
> + res->irq_resource,
> + res->irq_resource
> + + (sizeof(struct resource) * res->allocated_irqs)
> + + (sizeof(struct resource) * PNP_ALLOC_IRQ),
> + (unsigned long) (sizeof(struct resource) * res->allocated_irqs)
> + + (sizeof(struct resource) * PNP_ALLOC_IRQ),
> + (unsigned long) sizeof(struct resource),
> + res->allocated_irqs);
> + return 0;
> +}
> +
> +static int pnp_alloc_dma(struct pnp_resource_table *res)
> +{
> + int i;
> + void *ret;
> +
> + ret = krealloc(res->dma_resource,
> + (sizeof(struct resource) * res->allocated_dmas)
> + + (sizeof(struct resource) * PNP_ALLOC_DMA), GFP_KERNEL);
> +
> + if (!ret)
> + return -ENOMEM;
> +
> + res->dma_resource = ret;
> +
> + res->allocated_dmas += PNP_ALLOC_DMA;
> + for (i = res->allocated_dmas - PNP_ALLOC_DMA; i < res->allocated_dmas;
> + i++)
> + pnp_init_dma(&res->dma_resource[i]);
> +
> + pnp_dbg("Dma allocate: %p - %p; Allocated: %lu bytes, size of"
> + "struct: %lu - allocated dmas: %d",
> + res->dma_resource,
> + res->dma_resource
> + + (sizeof(struct resource) * res->allocated_dmas)
> + + (sizeof(struct resource) * PNP_ALLOC_DMA),
> + (unsigned long) (sizeof(struct resource) * res->allocated_dmas)
> + + (sizeof(struct resource) * PNP_ALLOC_DMA),
> + (unsigned long) sizeof(struct resource),
> + res->allocated_dmas);
> +
> + return 0;
> +}
> +
> +#define pnp_print_alloc_err(type, val, x) \
> + pnp_dbg("%s - cannot allocate new resource: %d in func %s " \
> + " - alloc: %d", type, val, __FUNCTION__, x)
> +
> +
> +/*
> + * Assign a resource (IO, MEM, IRQ, DMA) to the resource table.
> + * Searches for an IORESOURCE_UNSET resource entry in the table or reallocs
> + * new resource entries as needed and copies the given resource there.
> + */
> +int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res)
> +{
> + int i = 0, ret;
> +
> + if (!table || !res)
> + return -EINVAL;
> +
> + if (res->flags & IORESOURCE_IO) {
> + /* find the next unused table entry */
> + while (i < table->allocated_ports) {
> + if (!(table->port_resource[i].flags
> + & IORESOURCE_UNSET))
> + i++;
> + else
> + break;
> + }
> + /* No unused table entry anymore, allocate new ones */
> + if (table->allocated_ports <= i) {
> + ret = pnp_alloc_port(table);
> + if (ret) {
> + pnp_print_alloc_err("Port", ret, i);
> + return ret;
> + }
> + }
> + memcpy(&table->port_resource[i], res, sizeof(struct resource));
> + } else if (res->flags & IORESOURCE_MEM) {
> + while (i < table->allocated_mems) {
> + if (!(table->mem_resource[i].flags & IORESOURCE_UNSET))
> + i++;
> + else
> + break;
> + }
> +
> + if (table->allocated_mems <= i) {
> + ret = pnp_alloc_mem(table);
> + if (ret) {
> + pnp_print_alloc_err("System Memory", ret, i);
> + return ret;
> + }
> + }
> + memcpy(&table->mem_resource[i], res, sizeof(struct resource));
> + } else if (res->flags & IORESOURCE_IRQ) {
> + while (i < table->allocated_irqs) {
> + if (!(table->irq_resource[i].flags & IORESOURCE_UNSET))
> + i++;
> + else
> + break;
> + }
> +
> + if (table->allocated_irqs <= i) {
> + ret = pnp_alloc_irq(table);
> + if (ret) {
> + pnp_print_alloc_err("Irq", ret, i);
> + return ret;
> + }
> + }
> + memcpy(&table->irq_resource[i], res, sizeof(struct resource));
> + } else if (res->flags & IORESOURCE_DMA) {
> + while (i < table->allocated_dmas) {
> + if (!(table->dma_resource[i].flags & IORESOURCE_UNSET))
> + i++;
> + else
> + break;
> + }
> +
> + if (table->allocated_dmas <= i) {
> + ret = pnp_alloc_dma(table);
> + if (ret) {
> + pnp_print_alloc_err("DMA", ret, i);
> + return ret;
> + }
> + }
> + memcpy(&table->dma_resource[i], res, sizeof(struct resource));
> + } else
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +#define pnp_print_assign_err(type, val) \
> + pnp_dbg("%s resource %d not allocated, cannot assign value", \
> + type, val);
> +
> +
> +
> +static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
> +{
> + struct resource res;
>
> /* check if this resource has been manually set, if so skip */
> - if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
> + if (pnp_port_valid(dev, idx) && !(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
> return 1;
>
> - start = &dev->res.port_resource[idx].start;
> - end = &dev->res.port_resource[idx].end;
> - flags = &dev->res.port_resource[idx].flags;
> + if (pnp_port_valid(dev, idx)) {
> + /* This resource index already got some values assigned,
> + take them as init */
> + res.start = dev->res.port_resource[idx].start;
> + res.end = dev->res.port_resource[idx].end;
> + res.flags = dev->res.port_resource[idx].flags;
> + } else
> + /* This index in the table does not exist, initialize the new
> + resource and be carefuly to never access
> + dev->res.port_resource[idx] */
> + pnp_init_io(&res);
>
> /* set the initial values */
> - *flags |= rule->flags | IORESOURCE_IO;
> - *flags &= ~IORESOURCE_UNSET;
> + res.flags |= rule->flags | IORESOURCE_IO;
> + res.flags &= ~IORESOURCE_UNSET;
>
> if (!rule->size) {
> - *flags |= IORESOURCE_DISABLED;
> + res.flags |= IORESOURCE_DISABLED;
> + pnp_assign_resource(&dev->res, &res);
> return 1; /* skip disabled resource requests */
> }
>
> - *start = rule->min;
> - *end = *start + rule->size - 1;
> + res.start = rule->min;
> + res.end = res.start + rule->size - 1;
>
> /* run through until pnp_check_port is happy */
> while (!pnp_check_port(dev, idx)) {
> - *start += rule->align;
> - *end = *start + rule->size - 1;
> - if (*start > rule->max || !rule->align)
> - return 0;
> + res.start += rule->align;
> + res.end = res.start + rule->size - 1;
> + if (res.start > rule->max || !rule->align)
> + return pnp_assign_resource(&dev->res, &res);
> }
> + pnp_assign_resource(&dev->res, &res);
> return 1;
> }
>
> static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
> {
> - resource_size_t *start, *end;
> - unsigned long *flags;
> -
> - if (idx >= PNP_MAX_MEM) {
> - dev_err(&dev->dev, "too many memory resources\n");
> - /* pretend we were successful so at least the manager won't try again */
> - return 1;
> - }
> + struct resource res;
>
> /* check if this resource has been manually set, if so skip */
> - if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
> + if (pnp_mem_valid(dev, idx) && !(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
> return 1;
>
> - start = &dev->res.mem_resource[idx].start;
> - end = &dev->res.mem_resource[idx].end;
> - flags = &dev->res.mem_resource[idx].flags;
> + if (pnp_mem_valid(dev, idx)) {
> + res.start = dev->res.mem_resource[idx].start;
> + res.end = dev->res.mem_resource[idx].end;
> + res.flags = dev->res.mem_resource[idx].flags;
> + } else
> + pnp_init_mem(&res);
>
> /* set the initial values */
> - *flags |= rule->flags | IORESOURCE_MEM;
> - *flags &= ~IORESOURCE_UNSET;
> + res.flags |= rule->flags | IORESOURCE_MEM;
> + res.flags &= ~IORESOURCE_UNSET;
>
> /* convert pnp flags to standard Linux flags */
> if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
> - *flags |= IORESOURCE_READONLY;
> + res.flags |= IORESOURCE_READONLY;
> if (rule->flags & IORESOURCE_MEM_CACHEABLE)
> - *flags |= IORESOURCE_CACHEABLE;
> + res.flags |= IORESOURCE_CACHEABLE;
> if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
> - *flags |= IORESOURCE_RANGELENGTH;
> + res.flags |= IORESOURCE_RANGELENGTH;
> if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
> - *flags |= IORESOURCE_SHADOWABLE;
> + res.flags |= IORESOURCE_SHADOWABLE;
>
> if (!rule->size) {
> - *flags |= IORESOURCE_DISABLED;
> + res.flags |= IORESOURCE_DISABLED;
> + pnp_assign_resource(&dev->res, &res);
> return 1; /* skip disabled resource requests */
> }
>
> - *start = rule->min;
> - *end = *start + rule->size - 1;
> + res.start = rule->min;
> + res.end = res.start + rule->size - 1;
>
> /* run through until pnp_check_mem is happy */
> while (!pnp_check_mem(dev, idx)) {
> - *start += rule->align;
> - *end = *start + rule->size - 1;
> - if (*start > rule->max || !rule->align)
> - return 0;
> + res.start += rule->align;
> + res.end = res.start + rule->size - 1;
> + if (res.start > rule->max || !rule->align)
> + return pnp_assign_resource(&dev->res, &res);
> }
> + pnp_assign_resource(&dev->res, &res);
> return 1;
> }
>
> static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
> {
> - resource_size_t *start, *end;
> - unsigned long *flags;
> + struct resource res;
> int i;
>
> /* IRQ priority: this table is good for i386 */
> @@ -119,49 +442,47 @@ static int pnp_assign_irq(struct pnp_dev
> 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
> };
>
> - if (idx >= PNP_MAX_IRQ) {
> - dev_err(&dev->dev, "too many IRQ resources\n");
> - /* pretend we were successful so at least the manager won't try again */
> - return 1;
> - }
> -
> /* check if this resource has been manually set, if so skip */
> - if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
> + if (pnp_irq_valid(dev, idx) && !(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
> return 1;
>
> - start = &dev->res.irq_resource[idx].start;
> - end = &dev->res.irq_resource[idx].end;
> - flags = &dev->res.irq_resource[idx].flags;
> + if (pnp_irq_valid(dev, idx)) {
> + res.start = dev->res.irq_resource[idx].start;
> + res.end = dev->res.irq_resource[idx].end;
> + res.flags = dev->res.irq_resource[idx].flags;
> + } else
> + pnp_init_irq(&res);
>
> /* set the initial values */
> - *flags |= rule->flags | IORESOURCE_IRQ;
> - *flags &= ~IORESOURCE_UNSET;
> + res.flags |= rule->flags | IORESOURCE_IRQ;
> + res.flags &= ~IORESOURCE_UNSET;
>
> if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
> - *flags |= IORESOURCE_DISABLED;
> + res.flags |= IORESOURCE_DISABLED;
> + pnp_assign_resource(&dev->res, &res);
> return 1; /* skip disabled resource requests */
> }
>
> /* TBD: need check for >16 IRQ */
> - *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
> - if (*start < PNP_IRQ_NR) {
> - *end = *start;
> + res.start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
> + if (res.start < PNP_IRQ_NR) {
> + res.end = res.start;
> + pnp_assign_resource(&dev->res, &res);
> return 1;
> }
> for (i = 0; i < 16; i++) {
> if (test_bit(xtab[i], rule->map)) {
> - *start = *end = xtab[i];
> + res.start = res.end = xtab[i];
> if (pnp_check_irq(dev, idx))
> return 1;
> }
> }
> - return 0;
> + return pnp_assign_resource(&dev->res, &res);
> }
>
> static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
> {
> - resource_size_t *start, *end;
> - unsigned long *flags;
> + struct resource res;
> int i;
>
> /* DMA priority: this table is good for i386 */
> @@ -169,34 +490,35 @@ static void pnp_assign_dma(struct pnp_de
> 1, 3, 5, 6, 7, 0, 2, 4
> };
>
> - if (idx >= PNP_MAX_DMA) {
> - dev_err(&dev->dev, "too many DMA resources\n");
> - return;
> - }
> -
> /* check if this resource has been manually set, if so skip */
> - if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
> + if (pnp_dma_valid(dev, idx) && !(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
> return;
>
> - start = &dev->res.dma_resource[idx].start;
> - end = &dev->res.dma_resource[idx].end;
> - flags = &dev->res.dma_resource[idx].flags;
> + if (pnp_dma_valid(dev, idx)) {
> + res.start = dev->res.dma_resource[idx].start;
> + res.end = dev->res.dma_resource[idx].end;
> + res.flags = dev->res.dma_resource[idx].flags;
> + } else
> + pnp_init_dma(&res);
>
> /* set the initial values */
> - *flags |= rule->flags | IORESOURCE_DMA;
> - *flags &= ~IORESOURCE_UNSET;
> + res.flags |= rule->flags | IORESOURCE_DMA;
> + res.flags &= ~IORESOURCE_UNSET;
>
> for (i = 0; i < 8; i++) {
> if (rule->map & (1 << xtab[i])) {
> - *start = *end = xtab[i];
> - if (pnp_check_dma(dev, idx))
> + res.start = res.end = xtab[i];
> + if (pnp_check_dma(dev, idx)){
> + pnp_assign_resource(&dev->res, &res);
> return;
> + }
> }
> }
> #ifdef MAX_DMA_CHANNELS
> - *start = *end = MAX_DMA_CHANNELS;
> + res.start = res.end = MAX_DMA_CHANNELS;
> #endif
> - *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
> + res.flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
> + pnp_assign_resource(&dev->res, &res);
> }
>
> /**
> @@ -207,28 +529,28 @@ void pnp_init_resource_table(struct pnp_
> {
> int idx;
>
> - for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
> + for (idx = 0; idx < table->allocated_irqs; idx++) {
> table->irq_resource[idx].name = NULL;
> table->irq_resource[idx].start = -1;
> table->irq_resource[idx].end = -1;
> table->irq_resource[idx].flags =
> IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_DMA; idx++) {
> + for (idx = 0; idx < table->allocated_dmas; idx++) {
> table->dma_resource[idx].name = NULL;
> table->dma_resource[idx].start = -1;
> table->dma_resource[idx].end = -1;
> table->dma_resource[idx].flags =
> IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_PORT; idx++) {
> + for (idx = 0; idx < table->allocated_ports; idx++) {
> table->port_resource[idx].name = NULL;
> table->port_resource[idx].start = 0;
> table->port_resource[idx].end = 0;
> table->port_resource[idx].flags =
> IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_MEM; idx++) {
> + for (idx = 0; idx < table->allocated_mems; idx++) {
> table->mem_resource[idx].name = NULL;
> table->mem_resource[idx].start = 0;
> table->mem_resource[idx].end = 0;
> @@ -245,7 +567,7 @@ static void pnp_clean_resource_table(str
> {
> int idx;
>
> - for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
> + for (idx = 0; idx < res->allocated_irqs; idx++) {
> if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
> continue;
> res->irq_resource[idx].start = -1;
> @@ -253,7 +575,7 @@ static void pnp_clean_resource_table(str
> res->irq_resource[idx].flags =
> IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_DMA; idx++) {
> + for (idx = 0; idx < res->allocated_dmas; idx++) {
> if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
> continue;
> res->dma_resource[idx].start = -1;
> @@ -261,7 +583,7 @@ static void pnp_clean_resource_table(str
> res->dma_resource[idx].flags =
> IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_PORT; idx++) {
> + for (idx = 0; idx < res->allocated_ports; idx++) {
> if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
> continue;
> res->port_resource[idx].start = 0;
> @@ -269,7 +591,7 @@ static void pnp_clean_resource_table(str
> res->port_resource[idx].flags =
> IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
> }
> - for (idx = 0; idx < PNP_MAX_MEM; idx++) {
> + for (idx = 0; idx < res->allocated_mems; idx++) {
> if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
> continue;
> res->mem_resource[idx].start = 0;
> @@ -386,46 +708,12 @@ fail:
> int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
> int mode)
> {
> - int i;
> - struct pnp_resource_table *bak;
> -
> - if (!pnp_can_configure(dev))
> - return -ENODEV;
> - bak = pnp_alloc(sizeof(struct pnp_resource_table));
> - if (!bak)
> - return -ENOMEM;
> - *bak = dev->res;
> -
> - down(&pnp_res_mutex);
> - dev->res = *res;
> - if (!(mode & PNP_CONFIG_FORCE)) {
> - for (i = 0; i < PNP_MAX_PORT; i++) {
> - if (!pnp_check_port(dev, i))
> - goto fail;
> - }
> - for (i = 0; i < PNP_MAX_MEM; i++) {
> - if (!pnp_check_mem(dev, i))
> - goto fail;
> - }
> - for (i = 0; i < PNP_MAX_IRQ; i++) {
> - if (!pnp_check_irq(dev, i))
> - goto fail;
> - }
> - for (i = 0; i < PNP_MAX_DMA; i++) {
> - if (!pnp_check_dma(dev, i))
> - goto fail;
> - }
> - }
> - up(&pnp_res_mutex);
> -
> - kfree(bak);
> - return 0;
> + /* We must never end up here, these functions are poisson for dynamic
> + allocation via pointer array.
> + */
> + BUG_ON(1);
> + return 1;
>
> -fail:
> - dev->res = *bak;
> - up(&pnp_res_mutex);
> - kfree(bak);
> - return -EINVAL;
> }
>
> /**
> @@ -563,6 +851,7 @@ int pnp_disable_dev(struct pnp_dev *dev)
> void pnp_resource_change(struct resource *resource, resource_size_t start,
> resource_size_t size)
> {
> + return;
> resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
> resource->start = start;
> resource->end = start + size - 1;
> Index: linux-acpi-2.6/drivers/pnp/pnpacpi/rsparser.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/pnpacpi/rsparser.c
> +++ linux-acpi-2.6/drivers/pnp/pnpacpi/rsparser.c
> @@ -73,23 +73,16 @@ static void pnpacpi_parse_allocated_irqr
> u32 gsi, int triggering,
> int polarity, int shareable)
> {
> - int i = 0;
> int irq;
> int p, t;
> - static unsigned char warned;
> +
> + struct resource new_res = {
> + .flags = IORESOURCE_IRQ,
> + };
>
> if (!valid_IRQ(gsi))
> return;
>
> - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
> - i < PNP_MAX_IRQ)
> - i++;
> - if (i >= PNP_MAX_IRQ && !warned) {
> - printk(KERN_ERR "pnpacpi: exceeded the max number of IRQ "
> - "resources: %d \n", PNP_MAX_IRQ);
> - warned = 1;
> - return;
> - }
> /*
> * in IO-APIC mode, use overrided attribute. Two reasons:
> * 1. BIOS bug in DSDT
> @@ -107,20 +100,26 @@ static void pnpacpi_parse_allocated_irqr
> }
> }
>
> - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
> - res->irq_resource[i].flags |= irq_flags(triggering, polarity);
> + new_res.flags |= irq_flags(triggering, polarity);
> irq = acpi_register_gsi(gsi, triggering, polarity);
> if (irq < 0) {
> - res->irq_resource[i].flags |= IORESOURCE_DISABLED;
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> return;
> }
>
> if (shareable)
> - res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
> + new_res.flags |= IORESOURCE_IRQ_SHAREABLE;
>
> - res->irq_resource[i].start = irq;
> - res->irq_resource[i].end = irq;
> + new_res.start = irq;
> + new_res.end = irq;
> pcibios_penalize_isa_irq(irq, 1);
> +
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static int dma_flags(int type, int bus_master, int transfer)
> @@ -170,81 +169,71 @@ static void pnpacpi_parse_allocated_dmar
> u32 dma, int type,
> int bus_master, int transfer)
> {
> - int i = 0;
> - static unsigned char warned;
> -
> - while (i < PNP_MAX_DMA &&
> - !(res->dma_resource[i].flags & IORESOURCE_UNSET))
> - i++;
> - if (i < PNP_MAX_DMA) {
> - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
> - res->dma_resource[i].flags |=
> - dma_flags(type, bus_master, transfer);
> - if (dma == -1) {
> - res->dma_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->dma_resource[i].start = dma;
> - res->dma_resource[i].end = dma;
> - } else if (!warned) {
> - printk(KERN_ERR "pnpacpi: exceeded the max number of DMA "
> - "resources: %d \n", PNP_MAX_DMA);
> - warned = 1;
> - }
> + struct resource new_res = {
> + .flags = IORESOURCE_DMA,
> + };
> +
> + new_res.flags |= dma_flags(type, bus_master, transfer);
> + if (dma == -1) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> + }
> + new_res.start = dma;
> + new_res.end = dma;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
> u64 io, u64 len, int io_decode)
> {
> - int i = 0;
> - static unsigned char warned;
> -
> - while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
> - i < PNP_MAX_PORT)
> - i++;
> - if (i < PNP_MAX_PORT) {
> - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
> - if (io_decode == ACPI_DECODE_16)
> - res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
> - if (len <= 0 || (io + len - 1) >= 0x10003) {
> - res->port_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->port_resource[i].start = io;
> - res->port_resource[i].end = io + len - 1;
> - } else if (!warned) {
> - printk(KERN_ERR "pnpacpi: exceeded the max number of IO "
> - "resources: %d \n", PNP_MAX_PORT);
> - warned = 1;
> - }
> + struct resource new_res = {
> + .flags = IORESOURCE_IO,
> + };
> +
> + if (io_decode == ACPI_DECODE_16)
> + new_res.flags |= PNP_PORT_FLAG_16BITADDR;
> + if (len <= 0 || (io + len - 1) >= 0x10003) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> + }
> + new_res.start = io;
> + new_res.end = io + len - 1;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
> u64 mem, u64 len,
> int write_protect)
> {
> - int i = 0;
> - static unsigned char warned;
> -
> - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
> - (i < PNP_MAX_MEM))
> - i++;
> - if (i < PNP_MAX_MEM) {
> - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
> - if (len <= 0) {
> - res->mem_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - if (write_protect == ACPI_READ_WRITE_MEMORY)
> - res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
> -
> - res->mem_resource[i].start = mem;
> - res->mem_resource[i].end = mem + len - 1;
> - } else if (!warned) {
> - printk(KERN_ERR "pnpacpi: exceeded the max number of mem "
> - "resources: %d\n", PNP_MAX_MEM);
> - warned = 1;
> - }
> + struct resource new_res = {
> + .flags = IORESOURCE_MEM,
> + };
> +
> + if (len <= 0) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> + }
> + if (write_protect == ACPI_READ_WRITE_MEMORY)
> + new_res.flags |= IORESOURCE_MEM_WRITEABLE;
> +
> + new_res.start = mem;
> + new_res.end = mem + len - 1;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
> Index: linux-acpi-2.6/drivers/pnp/pnpbios/rsparser.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/pnpbios/rsparser.c
> +++ linux-acpi-2.6/drivers/pnp/pnpbios/rsparser.c
> @@ -56,78 +56,84 @@ inline void pcibios_penalize_isa_irq(int
> static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
> int irq)
> {
> - int i = 0;
> -
> - while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
> - && i < PNP_MAX_IRQ)
> - i++;
> - if (i < PNP_MAX_IRQ) {
> - res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
> - if (irq == -1) {
> - res->irq_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->irq_resource[i].start =
> - res->irq_resource[i].end = (unsigned long)irq;
> - pcibios_penalize_isa_irq(irq, 1);
> + struct resource new_res = {
> + .flags = IORESOURCE_IRQ,
> + };
> +
> + if (irq == -1) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> }
> + new_res.start = new_res.end = (unsigned long)irq;
> + pcibios_penalize_isa_irq(irq, 1);
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
> int dma)
> {
> - int i = 0;
> -
> - while (i < PNP_MAX_DMA &&
> - !(res->dma_resource[i].flags & IORESOURCE_UNSET))
> - i++;
> - if (i < PNP_MAX_DMA) {
> - res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
> - if (dma == -1) {
> - res->dma_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->dma_resource[i].start =
> - res->dma_resource[i].end = (unsigned long)dma;
> + struct resource new_res = {
> + .flags = IORESOURCE_DMA,
> + };
> +
> + if (dma == -1) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> }
> + new_res.start = new_res.end = (unsigned long)dma;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
> int io, int len)
> {
> - int i = 0;
> -
> - while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
> - && i < PNP_MAX_PORT)
> - i++;
> - if (i < PNP_MAX_PORT) {
> - res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
> - if (len <= 0 || (io + len - 1) >= 0x10003) {
> - res->port_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->port_resource[i].start = (unsigned long)io;
> - res->port_resource[i].end = (unsigned long)(io + len - 1);
> + struct resource new_res = {
> + .flags = IORESOURCE_IO,
> + };
> +
> + if (len <= 0 || (io + len - 1) >= 0x10003) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> }
> + new_res.start = (unsigned long)io;
> + new_res.end = (unsigned long)(io + len - 1);
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
> int mem, int len)
> {
> - int i = 0;
> -
> - while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
> - && i < PNP_MAX_MEM)
> - i++;
> - if (i < PNP_MAX_MEM) {
> - res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
> - if (len <= 0) {
> - res->mem_resource[i].flags |= IORESOURCE_DISABLED;
> - return;
> - }
> - res->mem_resource[i].start = (unsigned long)mem;
> - res->mem_resource[i].end = (unsigned long)(mem + len - 1);
> + struct resource new_res = {
> + .flags = IORESOURCE_MEM,
> + };
> +
> + if (len <= 0) {
> + /* <trenn> Check: Do we need to allocate and assign
> + this resource at all? */
> + new_res.flags |= IORESOURCE_DISABLED;
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> + return;
> }
> + new_res.start = (unsigned long)mem;
> + new_res.end = (unsigned long)(mem + len - 1);
> + if (pnp_assign_resource(res, &new_res))
> + pnp_err("Bug in %s", __FUNCTION__);
> }
>
> static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
> Index: linux-acpi-2.6/drivers/pnp/resource.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/resource.c
> +++ linux-acpi-2.6/drivers/pnp/resource.c
> @@ -242,7 +242,7 @@ int pnp_check_port(struct pnp_dev *dev,
> }
>
> /* check for internal conflicts */
> - for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
> + for (tmp = 0; pnp_port_valid(dev, tmp) && tmp != idx; tmp++) {
> if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
> tport = &dev->res.port_resource[tmp].start;
> tend = &dev->res.port_resource[tmp].end;
> @@ -255,7 +255,7 @@ int pnp_check_port(struct pnp_dev *dev,
> pnp_for_each_dev(tdev) {
> if (tdev == dev)
> continue;
> - for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
> + for (tmp = 0; pnp_port_valid(tdev, tmp); tmp++) {
> if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
> if (cannot_compare
> (tdev->res.port_resource[tmp].flags))
> @@ -300,7 +300,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
> }
>
> /* check for internal conflicts */
> - for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
> + for (tmp = 0; pnp_mem_valid(dev, tmp) && tmp != idx; tmp++) {
> if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
> taddr = &dev->res.mem_resource[tmp].start;
> tend = &dev->res.mem_resource[tmp].end;
> @@ -313,7 +313,7 @@ int pnp_check_mem(struct pnp_dev *dev, i
> pnp_for_each_dev(tdev) {
> if (tdev == dev)
> continue;
> - for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
> + for (tmp = 0; pnp_mem_valid(tdev, tmp); tmp++) {
> if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
> if (cannot_compare
> (tdev->res.mem_resource[tmp].flags))
> @@ -355,7 +355,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
> }
>
> /* check for internal conflicts */
> - for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
> + for (tmp = 0; pnp_irq_valid(dev, tmp) && tmp != idx; tmp++) {
> if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
> if (dev->res.irq_resource[tmp].start == *irq)
> return 0;
> @@ -388,7 +388,7 @@ int pnp_check_irq(struct pnp_dev *dev, i
> pnp_for_each_dev(tdev) {
> if (tdev == dev)
> continue;
> - for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
> + for (tmp = 0; pnp_irq_valid(tdev, tmp); tmp++) {
> if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
> if (cannot_compare
> (tdev->res.irq_resource[tmp].flags))
> @@ -424,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
> }
>
> /* check for internal conflicts */
> - for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
> + for (tmp = 0; pnp_dma_valid(dev, tmp) && tmp != idx; tmp++) {
> if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
> if (dev->res.dma_resource[tmp].start == *dma)
> return 0;
> @@ -443,7 +443,7 @@ int pnp_check_dma(struct pnp_dev *dev, i
> pnp_for_each_dev(tdev) {
> if (tdev == dev)
> continue;
> - for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
> + for (tmp = 0; pnp_dma_valid(tdev, tmp); tmp++) {
> if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
> if (cannot_compare
> (tdev->res.dma_resource[tmp].flags))
> Index: linux-acpi-2.6/drivers/pnp/support.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/support.c
> +++ linux-acpi-2.6/drivers/pnp/support.c
> @@ -14,11 +14,16 @@
> * resources
> * @dev: pointer to the desired PnP device
> */
> +
> +/* <trenn> This interface is only used by pnpbios and one driver:
> + sound/isa/sscape.c
> + drivers can check for pnp_port_valid... anyway
> + This one is not needed.
> +*/
> int pnp_is_active(struct pnp_dev *dev)
> {
> - if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
> - !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
> - pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
> + if (dev->res.allocated_ports <= 0 && dev->res.allocated_mems <= 0 &&
> + dev->res.allocated_irqs <= 0 && dev->res.allocated_dmas <= 0)
> return 0;
> else
> return 1;
> Index: linux-acpi-2.6/drivers/pnp/system.c
> ===================================================================
> --- linux-acpi-2.6.orig/drivers/pnp/system.c
> +++ linux-acpi-2.6/drivers/pnp/system.c
> @@ -58,7 +58,7 @@ static void reserve_resources_of_dev(str
> {
> int i;
>
> - for (i = 0; i < PNP_MAX_PORT; i++) {
> + for (i = 0; pnp_port_valid(dev, i); i++) {
> if (!pnp_port_valid(dev, i))
> continue;
> if (pnp_port_start(dev, i) == 0)
> @@ -80,7 +80,7 @@ static void reserve_resources_of_dev(str
> pnp_port_end(dev, i), 1);
> }
>
> - for (i = 0; i < PNP_MAX_MEM; i++) {
> + for (i = 0; pnp_mem_valid(dev, i); i++) {
> if (!pnp_mem_valid(dev, i))
> continue;
>
> Index: linux-acpi-2.6/include/linux/pnp.h
> ===================================================================
> --- linux-acpi-2.6.orig/include/linux/pnp.h
> +++ linux-acpi-2.6/include/linux/pnp.h
> @@ -13,10 +13,6 @@
> #include <linux/errno.h>
> #include <linux/mod_devicetable.h>
>
> -#define PNP_MAX_PORT 40
> -#define PNP_MAX_MEM 12
> -#define PNP_MAX_IRQ 2
> -#define PNP_MAX_DMA 2
> #define PNP_NAME_LEN 50
>
> struct pnp_protocol;
> @@ -26,12 +22,24 @@ struct pnp_dev;
> * Resource Management
> */
>
> -/* Use these instead of directly reading pnp_dev to get resource information */
> -#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
> -#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
> -#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
> -#define pnp_port_valid(dev,bar) \
> - ((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
> +/*
> + * NULL pointer alarm: always check with pnp_port_valid or pnp_port_valid before
> + * accessing start/end/flags/len values or you might access not allocated mem.
> + * Same for mem, irq and dma macros
> + *
> + * Pointers are not static and they might change, do not store addresses
> + * of resources in the pnp resource table!
> + */
> +
> +#define pnp_port_start(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].start \
> + : pnp_dbg("WARN: Port start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_port_end(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].end \
> + : pnp_dbg("WARN: Port end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_port_flags(dev,bar) (pnp_port_valid((dev),(bar)) ? (dev)->res.port_resource[(bar)].flags \
> + : pnp_dbg("WARN: Port flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_port_valid(dev,bar) \
> + (((dev)->res.allocated_ports > (bar)) && \
> + (((dev)->res.port_resource[(bar)].flags) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
> == IORESOURCE_IO)
> #define pnp_port_len(dev,bar) \
> ((pnp_port_start((dev),(bar)) == 0 && \
> @@ -41,11 +49,15 @@ struct pnp_dev;
> (pnp_port_end((dev),(bar)) - \
> pnp_port_start((dev),(bar)) + 1))
>
> -#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
> -#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
> -#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
> +#define pnp_mem_start(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].start \
> + : pnp_dbg("Mem start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_mem_end(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].end \
> + : pnp_dbg("Mem end %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_mem_flags(dev,bar) (pnp_mem_valid((dev),(bar)) ? (dev)->res.mem_resource[(bar)].flags \
> + : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> #define pnp_mem_valid(dev,bar) \
> - ((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
> + (((dev)->res.allocated_mems > (bar)) && \
> + (((dev)->res.mem_resource[(bar)].flags) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
> == IORESOURCE_MEM)
> #define pnp_mem_len(dev,bar) \
> ((pnp_mem_start((dev),(bar)) == 0 && \
> @@ -55,16 +67,22 @@ struct pnp_dev;
> (pnp_mem_end((dev),(bar)) - \
> pnp_mem_start((dev),(bar)) + 1))
>
> -#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
> -#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
> +#define pnp_irq(dev,bar) (pnp_irq_valid((dev),(bar)) ? (dev)->res.irq_resource[(bar)].start \
> + : pnp_dbg("Irq start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_irq_flags(dev,bar) (pnp_irq_valid((dev),(bar)) ? (dev)->res.irq_resource[(bar)].flags \
> + : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> #define pnp_irq_valid(dev,bar) \
> - ((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
> + (((dev)->res.allocated_irqs > (bar)) && \
> + (((dev)->res.irq_resource[(bar)].flags) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
> == IORESOURCE_IRQ)
>
> -#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
> -#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
> +#define pnp_dma(dev,bar) (pnp_dma_valid((dev),(bar)) ? (dev)->res.dma_resource[(bar)].start \
> + : pnp_dbg("Dma start %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> +#define pnp_dma_flags(dev,bar) (pnp_dma_valid((dev),(bar)) ? (dev)->res.dma_resource[(bar)].flags \
> + : pnp_dbg("Mem flags %d - [%s] invalid - %s:%d", (bar), (dev->name), __FUNCTION__, __LINE__))
> #define pnp_dma_valid(dev,bar) \
> - ((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
> + (((dev)->res.allocated_dmas > (bar)) && \
> + (((dev)->res.dma_resource[(bar)].flags) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
> == IORESOURCE_DMA)
>
> #define PNP_PORT_FLAG_16BITADDR (1<<0)
> @@ -119,10 +137,14 @@ struct pnp_option {
> };
>
> struct pnp_resource_table {
> - struct resource port_resource[PNP_MAX_PORT];
> - struct resource mem_resource[PNP_MAX_MEM];
> - struct resource dma_resource[PNP_MAX_DMA];
> - struct resource irq_resource[PNP_MAX_IRQ];
> + struct resource *port_resource;
> + unsigned int allocated_ports;
> + struct resource *mem_resource;
> + unsigned int allocated_mems;
> + struct resource *dma_resource;
> + unsigned int allocated_dmas;
> + struct resource *irq_resource;
> + unsigned int allocated_irqs;
> };
>
> /*
> @@ -364,6 +386,7 @@ int pnp_device_attach(struct pnp_dev *pn
> void pnp_device_detach(struct pnp_dev *pnp_dev);
> extern struct list_head pnp_global;
> extern int pnp_platform_devices;
> +extern int pnp_bios_data_parsed;
>
> /* multidevice card support */
> int pnp_add_card(struct pnp_card *card);
> @@ -398,6 +421,8 @@ int pnp_activate_dev(struct pnp_dev *dev
> int pnp_disable_dev(struct pnp_dev *dev);
> void pnp_resource_change(struct resource *resource, resource_size_t start,
> resource_size_t size);
> +int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res);
> +
>
> /* protocol helpers */
> int pnp_is_active(struct pnp_dev *dev);
> @@ -445,6 +470,7 @@ static inline int pnp_stop_dev(struct pn
> static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
> static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
> static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { }
> +static inline int pnp_assign_resource(struct pnp_resource_table *table, struct resource *res) { }
>
> /* protocol helpers */
> static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
> @@ -460,9 +486,11 @@ static inline void pnp_unregister_driver
> #define pnp_warn(format, arg...) printk(KERN_WARNING "pnp: " format "\n" , ## arg)
>
> #ifdef CONFIG_PNP_DEBUG
> -#define pnp_dbg(format, arg...) printk(KERN_DEBUG "pnp: " format "\n" , ## arg)
> +#define pnp_dbg(format, arg...) printk(KERN_INFO "pnp: " format "\n" , ## arg)
> +void pnp_dump_resources(struct pnp_dev *dev);
> #else
> #define pnp_dbg(format, arg...) do {} while (0)
> +static inline void pnp_dump_resources(struct pnp_dev *dev) { }
> #endif
>
> #endif /* __KERNEL__ */
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2008-02-06 15:21:15

by Rene Herman

[permalink] [raw]
Subject: Re: [PATCH] Allocate pnp resources dynamically via krealloc - Yet another Version

On 06-02-08 15:38, Thomas Renninger wrote:

> I expect on Rene's machine (might be something else, but this probably
> often happens), BIOS exports dma and IO ports. The irq seem to be
> missing and the driver does not use pnp_irq_valid, but pnp_irq. It

No. Please note we're talking about ISAPnP, not PnPBIOS. No BIOS involved at
all.

Driver (sound/isa/cs423x/cs4236.c) furthermore does not use anything but the
PnP layer itself. Start at snd_cs423x_pnpc_detect, which is the pnp .probe()
method.

I'll look into providing a more extensive answer and/or test whatever comes
in later.

Rene.