Bug 6292 - snd-ad1816a: Unable to assign resources to device 01:01.00
snd-ad1816a: Unable to assign resources to device 01:01.00
Status: RESOLVED CODE_FIX
Product: Drivers
Classification: Unclassified
Component: PNP
i386 Linux
: P2 normal
Assigned To: Adam Belay
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2006-03-27 09:40 UTC by Bjorn Helgaas
Modified: 2007-09-18 14:22 UTC (History)
5 users (show)

See Also:
Kernel Version: 2.6.16-mm1
Tree: Mainline
Regression: ---


Attachments
dmesg 2.6.16 (9.51 KB, text/plain)
2006-03-27 09:43 UTC, Bjorn Helgaas
Details
dmesg 2.6.16-mm1 (11.06 KB, text/plain)
2006-03-27 09:44 UTC, Bjorn Helgaas
Details
2.6.16 iomem, ioports, interrupts (2.85 KB, text/plain)
2006-04-03 08:16 UTC, Bjorn Helgaas
Details
2.6.16-mm2 iomem, ioports, interrupts (2.44 KB, text/plain)
2006-04-03 08:19 UTC, Bjorn Helgaas
Details
2.6.16 PNP resources (4.51 KB, text/plain)
2006-04-07 07:59 UTC, Bjorn Helgaas
Details
2.6.16-mm2 PNP resources (4.42 KB, text/plain)
2006-04-07 08:01 UTC, Bjorn Helgaas
Details
DSDT (binary) (8.15 KB, application/octet-stream)
2006-04-13 08:09 UTC, Bjorn Helgaas
Details
DSDT (disassembled) (85.63 KB, text/plain)
2006-04-13 08:09 UTC, Bjorn Helgaas
Details
my dsdt my bios update (9.94 KB, application/octet-stream)
2006-04-13 10:06 UTC, CASTET Matthieu
Details
correct resources printf (1.09 KB, patch)
2006-04-14 14:09 UTC, CASTET Matthieu
Details | Diff
2.6.17-rc1-mm3 debugging patch (3.28 KB, patch)
2006-04-20 21:19 UTC, Bjorn Helgaas
Details | Diff
balcklist pnp0a03 device (333 bytes, patch)
2006-04-21 10:55 UTC, CASTET Matthieu
Details | Diff
patch against 2.6.17-rc6-mm2 that should solve the problem (1020 bytes, patch)
2006-06-10 14:21 UTC, CASTET Matthieu
Details | Diff

Description Bjorn Helgaas 2006-03-27 09:40:55 UTC
Most recent kernel where this bug did not occur: 2.6.16   
   
Full dmesg logs attached.  With 2.6.16:   
  pnp: Device 01:01.00 activated.   
  pnp: Device 01:01.01 activated.   
   
With 2.6.16-mm1:   
  pnp: Unable to assign resources to device 01:01.00.   
  ad1816a: AUDIO PnP configure failure   
  no AD1816A based soundcards found.   
   
Uwe, can you also attach the output of "lspnp -v" and the contents  
of /proc/iomem, /proc/ioports, and /proc/interrupts?  Thanks.  
  
If you don't have it installed already, lspnp is in the 
pnpbios-tools package.
Comment 1 Bjorn Helgaas 2006-03-27 09:43:24 UTC
Created attachment 7687 [details]
dmesg 2.6.16
Comment 2 Bjorn Helgaas 2006-03-27 09:44:12 UTC
Created attachment 7688 [details]
dmesg 2.6.16-mm1
Comment 3 CASTET Matthieu 2006-03-27 11:14:03 UTC
if you doesn't have lspnp, a `for i in /sys/bus/pnp/devices/*; do echo $i; cat
$i/id; cat $i/resources; cat $i/options; done' could be really usefull.

Comment 4 Bjorn Helgaas 2006-04-03 08:16:06 UTC
Created attachment 7751 [details]
2.6.16 iomem, ioports, interrupts
Comment 5 Bjorn Helgaas 2006-04-03 08:19:03 UTC
Created attachment 7752 [details]
2.6.16-mm2 iomem, ioports, interrupts

I don't see any clues in these logs.  Uwe, could you try
Matthieu's idea from comment #3?
Comment 6 Bjorn Helgaas 2006-04-07 07:59:38 UTC
Created attachment 7805 [details]
2.6.16 PNP resources
Comment 7 Bjorn Helgaas 2006-04-07 08:01:23 UTC
Created attachment 7806 [details]
2.6.16-mm2 PNP resources

Note that all the io and mem resources here end with 0:

-Kernel 2.6.16
+Kernel 2.6.16-mm2
 /sys/bus/pnp/devices/00:00
 PNP0a03
 state = active
-io 0xcf8-0xcff
-mem 0x0-0xff
-mem 0x0-0xcf7
-mem 0xd00-0xffff
-mem 0xa0000-0xbffff
+io 0x0-0x0
+io 0xd00-0x0
+io 0xcf8-0x0
+mem 0xa0000-0x0
+mem 0xc8000-0x0
+mem 0x20000000-0x0
Comment 8 CASTET Matthieu 2006-04-07 12:34:37 UTC
Could you try with 2.6.17-rc1 ?
Comment 9 Bjorn Helgaas 2006-04-13 08:09:22 UTC
Created attachment 7861 [details]
DSDT (binary)

the machine is a Pentium 3 with 600 Mhz and 512 MB RAM, the mainboard is an
old Siemens-Fujitsu D 1107, the BIOS is a Phoenix one, Version 4.06,
Revision 1.11.1107.
Comment 10 Bjorn Helgaas 2006-04-13 08:09:58 UTC
Created attachment 7862 [details]
DSDT (disassembled)
Comment 11 CASTET Matthieu 2006-04-13 10:04:43 UTC
That's funny, I have some D 1107 here. I don't remebered that it support isa bus.

I have done some bios update on it and my dsdt is different from the attached one.

Bjorn Helgaas do you find some bug on it ?
Comment 12 CASTET Matthieu 2006-04-13 10:06:11 UTC
Created attachment 7863 [details]
my dsdt my bios update

I attach my binnay dsdt for reference.
Comment 13 CASTET Matthieu 2006-04-13 10:08:58 UTC
Sorry mine was a D1170
Comment 14 Bjorn Helgaas 2006-04-13 12:25:14 UTC
On Thursday 13 April 2006 08:52, Uwe Bugla wrote:
> the machine is a Pentium 3 with 600 Mhz and 512 MB RAM, the mainboard is an
> old Siemens-Fujitsu D 1107, the BIOS is a Phoenix one, Version 4.06,
> Revision 1.11.1107.
> I'd deeply would request you to offer a solution now instead of keeping on
> bugging me with sending in dmesgs, proc outputs, acpi outputs.

OK, I'm tired of this.  All you want is a solution to your problem,
and you don't care whether it breaks other machines.  And you want
me to just dream up a solution out of thin air, without the necessary
information about your machine.

> "If you take 2.6.17-rc1-mm2 and revert this patch:
> http://marc.theaimsgroup.com/?l=linux-acpi&m=113890268621542&w=2
> I assume your sound card works. is that correct?"
> 
> Bjorn, your question is not precise enough.

Oh?  Well, maybe you can tell me which part is ambiguous.  Or maybe
you can just tell me what I need to know without my having to ask.

All I can do is guess that the above patch is the issue, since you
won't confirm it.  The patch affects only address range descriptors,
so I expected to find some of them in your DSDT.  But here is a
sample of what your DSDT contains:

                Device (MBRD)
                {
                    Name (_HID, EisaId ("PNP0C02"))
                    Name (_STA, 0x0F)
                    Name (_CRS, ResourceTemplate ()
                    {       
                        IO (Decode16,
                            0x0010,             // Address Range Minimum
                            0x0010,             // Address Range Maximum
                            0x01,               // Address Alignment
                            0x10,               // Address Length
                            )

The "IO" section is a garden-variety I/O port descriptor, not an
address range descriptor.  Here is the AML from your acpidump.out:

  1450:                            47 01 10 00 10 00 01      .N...G......
  1460: 10                                               .G."."...G.P.P..

So I don't understand why the patch above affects this resource.  But
apparently it does, because without the patch, you get:

  io 0x10-0x1f

and with the patch, you get:

  io 0x10-0x0

Why?  I have no idea.  Maybe it will come to me sometime.  At the
moment, I have more interesting problems to work on.

Bjorn

Comment 15 Anonymous Emailer 2006-04-13 14:07:46 UTC
Reply-To: castet.matthieu@free.fr

Hi Uwe,

could you try with the attached rsparser.c ?

Then report the dmesg.

Thanks

Matthieu
/*
 * pnpacpi -- PnP ACPI driver
 *
 * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
 * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
#include "pnpacpi.h"

#ifdef CONFIG_IA64
#define valid_IRQ(i) (1)
#else
#define valid_IRQ(i) (((i) != 0) && ((i) != 2))
#endif

/*
 * Allocated Resources
 */
static int irq_flags(int triggering, int polarity)
{
	int flag;
	if (triggering == ACPI_LEVEL_SENSITIVE) {
		if (polarity == ACPI_ACTIVE_LOW)
			flag = IORESOURCE_IRQ_LOWLEVEL;
		else
			flag = IORESOURCE_IRQ_HIGHLEVEL;
	}
	else {
		if (polarity == ACPI_ACTIVE_LOW)
			flag = IORESOURCE_IRQ_LOWEDGE;
		else
			flag = IORESOURCE_IRQ_HIGHEDGE;
	}
	return flag;
}

static void decode_irq_flags(int flag, int *triggering, int *polarity)
{
	switch (flag) {
	case IORESOURCE_IRQ_LOWLEVEL:
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
		break;
	case IORESOURCE_IRQ_HIGHLEVEL:
		*triggering = ACPI_LEVEL_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
		break;
	case IORESOURCE_IRQ_LOWEDGE:
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_LOW;
		break;
	case IORESOURCE_IRQ_HIGHEDGE:
		*triggering = ACPI_EDGE_SENSITIVE;
		*polarity = ACPI_ACTIVE_HIGH;
		break;
	}
}

static void
pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
	int triggering, int polarity)
{
	int i = 0;
	int irq;

	if (!valid_IRQ(gsi))
		return;

	while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
			i < PNP_MAX_IRQ)
		i++;
	if (i >= PNP_MAX_IRQ)
		return;

	res->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
	irq = acpi_register_gsi(gsi, triggering, polarity);
	if (irq < 0) {
		res->irq_resource[i].flags |= IORESOURCE_DISABLED;
		return;
	}

	res->irq_resource[i].start = irq;
	res->irq_resource[i].end = irq;
	pcibios_penalize_isa_irq(irq, 1);
}

static void
pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, u32 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 = dma;
		res->dma_resource[i].end = dma;
	}
}

static void
pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
	u64 io, u64 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 = io;
		res->port_resource[i].end = io + len - 1;
	}
}

static void
pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
	u64 mem, u64 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 = mem;
		res->mem_resource[i].end = mem + len - 1;
	}
}

static void
pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
	struct acpi_resource *res)
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;

	status = acpi_resource_to_address64(res, p);
	if (!ACPI_SUCCESS(status)) {
		pnp_warn("PnPACPI: failed to convert resource type %d",
			res->type);
		return;
	}

	pnp_warn("ADDRESS %x %x %x\n", p->minimum, p->address_length, p->resource_type);

	if (p->resource_type == ACPI_MEMORY_RANGE)
		pnpacpi_parse_allocated_memresource(res_table,
				p->minimum, p->address_length);
	else if (p->resource_type == ACPI_IO_RANGE)
		pnpacpi_parse_allocated_ioresource(res_table,
				p->minimum, p->address_length);
}

static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
	void *data)
{
	struct pnp_resource_table *res_table = (struct pnp_resource_table *)data;
	int i;

	switch (res->type) {
	case ACPI_RESOURCE_TYPE_IRQ:
		/*
		 * Per spec, only one interrupt per descriptor is allowed in
		 * _CRS, but some firmware violates this, so parse them all.
		 */
		for (i = 0; i < res->data.irq.interrupt_count; i++) {
			pnpacpi_parse_allocated_irqresource(res_table,
				res->data.irq.interrupts[i],
				res->data.irq.triggering,
				res->data.irq.polarity);
		}
		break;

	case ACPI_RESOURCE_TYPE_DMA:
		if (res->data.dma.channel_count > 0)
			pnpacpi_parse_allocated_dmaresource(res_table,
					res->data.dma.channels[0]);
		break;

	case ACPI_RESOURCE_TYPE_IO:
		pnpacpi_parse_allocated_ioresource(res_table,
				res->data.io.minimum,
				res->data.io.address_length);
		break;

	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		break;

	case ACPI_RESOURCE_TYPE_FIXED_IO:
		pnpacpi_parse_allocated_ioresource(res_table,
				res->data.fixed_io.address,
				res->data.fixed_io.address_length);
		break;

	case ACPI_RESOURCE_TYPE_VENDOR:
		break;

	case ACPI_RESOURCE_TYPE_END_TAG:
		break;

	case ACPI_RESOURCE_TYPE_MEMORY24:
		pnpacpi_parse_allocated_memresource(res_table,
				res->data.memory24.minimum,
				res->data.memory24.address_length);
		break;
	case ACPI_RESOURCE_TYPE_MEMORY32:
		pnpacpi_parse_allocated_memresource(res_table,
				res->data.memory32.minimum,
				res->data.memory32.address_length);
		break;
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
		pnpacpi_parse_allocated_memresource(res_table,
				res->data.fixed_memory32.address,
				res->data.fixed_memory32.address_length);
		break;
	case ACPI_RESOURCE_TYPE_ADDRESS16:
		pnp_warn("ADDRESS16 %x %x %x\n", res->data.address16.minimum, res->data.address16.address_length, res->data.address16.resource_type);
	case ACPI_RESOURCE_TYPE_ADDRESS32:
		pnp_warn("ADDRESS32 %x %x %x\n", res->data.address32.minimum, res->data.address32.address_length, res->data.address32.resource_type);
	case ACPI_RESOURCE_TYPE_ADDRESS64:
		pnp_warn("ADDRESS64 %x %x %x\n", res->data.address64.minimum, res->data.address64.address_length, res->data.address64.resource_type);
		pnpacpi_parse_allocated_address_space(res_table, res);
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
		break;

	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
		for (i = 0; i < res->data.extended_irq.interrupt_count; i++) {
			pnpacpi_parse_allocated_irqresource(res_table,
				res->data.extended_irq.interrupts[i],
				res->data.extended_irq.triggering,
				res->data.extended_irq.polarity);
		}
		break;

	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		break;

	default:
		pnp_warn("PnPACPI: unknown resource type %d", res->type);
		return AE_ERROR;
	}

	return AE_OK;
}

acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table *res)
{
	/* Blank the resource table values */
	pnp_init_resource_table(res);

	return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
}

static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
{
	int i;
	struct pnp_dma * dma;

	if (p->channel_count == 0)
		return;
	dma = kcalloc(1, sizeof(struct pnp_dma), GFP_KERNEL);
	if (!dma)
		return;

	for(i = 0; i < p->channel_count; i++)
		dma->map |= 1 << p->channels[i];
	dma->flags = 0;
	if (p->bus_master)
		dma->flags |= IORESOURCE_DMA_MASTER;
	switch (p->type) {
	case ACPI_COMPATIBILITY:
		dma->flags |= IORESOURCE_DMA_COMPATIBLE;
		break;
	case ACPI_TYPE_A:
		dma->flags |= IORESOURCE_DMA_TYPEA;
		break;
	case ACPI_TYPE_B:
		dma->flags |= IORESOURCE_DMA_TYPEB;
		break;
	case ACPI_TYPE_F:
		dma->flags |= IORESOURCE_DMA_TYPEF;
		break;
	default:
		/* Set a default value ? */
		dma->flags |= IORESOURCE_DMA_COMPATIBLE;
		pnp_err("Invalid DMA type");
	}
	switch (p->transfer) {
	case ACPI_TRANSFER_8:
		dma->flags |= IORESOURCE_DMA_8BIT;
		break;
	case ACPI_TRANSFER_8_16:
		dma->flags |= IORESOURCE_DMA_8AND16BIT;
		break;
	case ACPI_TRANSFER_16:
		dma->flags |= IORESOURCE_DMA_16BIT;
		break;
	default:
		/* Set a default value ? */
		dma->flags |= IORESOURCE_DMA_8AND16BIT;
		pnp_err("Invalid DMA transfer type");
	}

	pnp_register_dma_resource(option, dma);
	return;
}


static void pnpacpi_parse_irq_option(struct pnp_option *option,
	struct acpi_resource_irq *p)
{
	int i;
	struct pnp_irq *irq;

	if (p->interrupt_count == 0)
		return;
	irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
	if (!irq)
		return;

	for(i = 0; i < p->interrupt_count; i++)
		if (p->interrupts[i])
			__set_bit(p->interrupts[i], irq->map);
	irq->flags = irq_flags(p->triggering, p->polarity);

	pnp_register_irq_resource(option, irq);
	return;
}

static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
	struct acpi_resource_extended_irq *p)
{
	int i;
	struct pnp_irq *irq;

	if (p->interrupt_count == 0)
		return;
	irq = kcalloc(1, sizeof(struct pnp_irq), GFP_KERNEL);
	if (!irq)
		return;

	for(i = 0; i < p->interrupt_count; i++)
		if (p->interrupts[i])
			__set_bit(p->interrupts[i], irq->map);
	irq->flags = irq_flags(p->triggering, p->polarity);

	pnp_register_irq_resource(option, irq);
	return;
}

static void
pnpacpi_parse_port_option(struct pnp_option *option,
	struct acpi_resource_io *io)
{
	struct pnp_port *port;

	if (io->address_length == 0)
		return;
	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
	if (!port)
		return;
	port->min = io->minimum;
	port->max = io->maximum;
	port->align = io->alignment;
	port->size = io->address_length;
	port->flags = ACPI_DECODE_16 == io->io_decode ?
		PNP_PORT_FLAG_16BITADDR : 0;
	pnp_register_port_resource(option, port);
	return;
}

static void
pnpacpi_parse_fixed_port_option(struct pnp_option *option,
	struct acpi_resource_fixed_io *io)
{
	struct pnp_port *port;

	if (io->address_length == 0)
		return;
	port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
	if (!port)
		return;
	port->min = port->max = io->address;
	port->size = io->address_length;
	port->align = 0;
	port->flags = PNP_PORT_FLAG_FIXED;
	pnp_register_port_resource(option, port);
	return;
}

static void
pnpacpi_parse_mem24_option(struct pnp_option *option,
	struct acpi_resource_memory24 *p)
{
	struct pnp_mem *mem;

	if (p->address_length == 0)
		return;
	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
	if (!mem)
		return;
	mem->min = p->minimum;
	mem->max = p->maximum;
	mem->align = p->alignment;
	mem->size = p->address_length;

	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
			IORESOURCE_MEM_WRITEABLE : 0;

	pnp_register_mem_resource(option, mem);
	return;
}

static void
pnpacpi_parse_mem32_option(struct pnp_option *option,
	struct acpi_resource_memory32 *p)
{
	struct pnp_mem *mem;

	if (p->address_length == 0)
		return;
	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
	if (!mem)
		return;
	mem->min = p->minimum;
	mem->max = p->maximum;
	mem->align = p->alignment;
	mem->size = p->address_length;

	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
			IORESOURCE_MEM_WRITEABLE : 0;

	pnp_register_mem_resource(option, mem);
	return;
}

static void
pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
	struct acpi_resource_fixed_memory32 *p)
{
	struct pnp_mem *mem;

	if (p->address_length == 0)
		return;
	mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
	if (!mem)
		return;
	mem->min = mem->max = p->address;
	mem->size = p->address_length;
	mem->align = 0;

	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
			IORESOURCE_MEM_WRITEABLE : 0;

	pnp_register_mem_resource(option, mem);
	return;
}

static void
pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
{
	struct acpi_resource_address64 addr, *p = &addr;
	acpi_status status;
	struct pnp_mem *mem;
	struct pnp_port *port;

	status = acpi_resource_to_address64(r, p);
	if (!ACPI_SUCCESS(status)) {
		pnp_warn("PnPACPI: failed to convert resource type %d", r->type);
		return;
	}
	pnp_warn("ADDRESS %x %x %x\n", p->address.minimum, p->address.address_length, p->address.resource_type);

	if (p->address_length == 0)
		return;

	if (p->resource_type == ACPI_MEMORY_RANGE) {
		mem = kcalloc(1, sizeof(struct pnp_mem), GFP_KERNEL);
		if (!mem)
			return;
		mem->min = mem->max = p->minimum;
		mem->size = p->address_length;
		mem->align = 0;
		mem->flags = (p->info.mem.write_protect ==
		    ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0;
		pnp_register_mem_resource(option, mem);
	} else if (p->resource_type == ACPI_IO_RANGE) {
		port = kcalloc(1, sizeof(struct pnp_port), GFP_KERNEL);
		if (!port)
			return;
		port->min = port->max = p->minimum;
		port->size = p->address_length;
		port->align = 0;
		port->flags = PNP_PORT_FLAG_FIXED;
		pnp_register_port_resource(option, port);
	}
}

struct acpipnp_parse_option_s {
	struct pnp_option *option;
	struct pnp_option *option_independent;
	struct pnp_dev *dev;
};

static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
	void *data)
{
	int priority = 0;
	struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
	struct pnp_dev *dev = parse_data->dev;
	struct pnp_option *option = parse_data->option;

	switch (res->type) {
		case ACPI_RESOURCE_TYPE_IRQ:
			pnpacpi_parse_irq_option(option, &res->data.irq);
			break;

		case ACPI_RESOURCE_TYPE_DMA:
			pnpacpi_parse_dma_option(option, &res->data.dma);
			break;

		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
			switch (res->data.start_dpf.compatibility_priority) {
				case ACPI_GOOD_CONFIGURATION:
					priority = PNP_RES_PRIORITY_PREFERRED;
					break;

				case ACPI_ACCEPTABLE_CONFIGURATION:
					priority = PNP_RES_PRIORITY_ACCEPTABLE;
					break;

				case ACPI_SUB_OPTIMAL_CONFIGURATION:
					priority = PNP_RES_PRIORITY_FUNCTIONAL;
					break;
				default:
					priority = PNP_RES_PRIORITY_INVALID;
					break;
			}
			/* TBD: Considering performace/robustness bits */
			option = pnp_register_dependent_option(dev, priority);
			if (!option)
				return AE_ERROR;
			parse_data->option = option;
			break;

		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
			/*only one EndDependentFn is allowed*/
			if (!parse_data->option_independent) {
				pnp_warn("PnPACPI: more than one EndDependentFn");
				return AE_ERROR;
			}
			parse_data->option = parse_data->option_independent;
			parse_data->option_independent = NULL;
			break;

		case ACPI_RESOURCE_TYPE_IO:
			pnpacpi_parse_port_option(option, &res->data.io);
			break;

		case ACPI_RESOURCE_TYPE_FIXED_IO:
			pnpacpi_parse_fixed_port_option(option,
				&res->data.fixed_io);
			break;

		case ACPI_RESOURCE_TYPE_VENDOR:
		case ACPI_RESOURCE_TYPE_END_TAG:
			break;

		case ACPI_RESOURCE_TYPE_MEMORY24:
			pnpacpi_parse_mem24_option(option, &res->data.memory24);
			break;

		case ACPI_RESOURCE_TYPE_MEMORY32:
			pnpacpi_parse_mem32_option(option, &res->data.memory32);
			break;

		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
			pnpacpi_parse_fixed_mem32_option(option,
				&res->data.fixed_memory32);
			break;

		case ACPI_RESOURCE_TYPE_ADDRESS16:
			pnp_warn("ADDRESS16 %x %x %x\n", res->data.address16.minimum, res->data.address16.address_length, res->data.address16.resource_type);
		case ACPI_RESOURCE_TYPE_ADDRESS32:
			pnp_warn("ADDRESS32 %x %x %x\n", res->data.address32.minimum, res->data.address32.address_length, res->data.address32.resource_type);
		case ACPI_RESOURCE_TYPE_ADDRESS64:
			pnp_warn("ADDRESS64 %x %x %x\n", res->data.address64.minimum, res->data.address64.address_length, res->data.address64.resource_type);
			pnpacpi_parse_address_option(option, res);
			break;

		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
			break;

		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
			pnpacpi_parse_ext_irq_option(option,
				&res->data.extended_irq);
			break;

		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
			break;

		default:
			pnp_warn("PnPACPI: unknown resource type %d", res->type);
			return AE_ERROR;
	}

	return AE_OK;
}

acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
	struct pnp_dev *dev)
{
	acpi_status status;
	struct acpipnp_parse_option_s parse_data;

	parse_data.option = pnp_register_independent_option(dev);
	if (!parse_data.option)
		return AE_ERROR;
	parse_data.option_independent = parse_data.option;
	parse_data.dev = dev;
	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
		pnpacpi_option_resource, &parse_data);

	return status;
}

static int pnpacpi_supported_resource(struct acpi_resource *res)
{
	switch (res->type) {
	case ACPI_RESOURCE_TYPE_IRQ:
	case ACPI_RESOURCE_TYPE_DMA:
	case ACPI_RESOURCE_TYPE_IO:
	case ACPI_RESOURCE_TYPE_FIXED_IO:
	case ACPI_RESOURCE_TYPE_MEMORY24:
	case ACPI_RESOURCE_TYPE_MEMORY32:
	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
	case ACPI_RESOURCE_TYPE_ADDRESS16:
	case ACPI_RESOURCE_TYPE_ADDRESS32:
	case ACPI_RESOURCE_TYPE_ADDRESS64:
	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
		return 1;
	}
	return 0;
}

/*
 * Set resource
 */
static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
	void *data)
{
	int *res_cnt = (int *)data;

	if (pnpacpi_supported_resource(res))
		(*res_cnt)++;
	return AE_OK;
}

static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
{
	struct acpi_resource **resource = (struct acpi_resource **)data;

	if (pnpacpi_supported_resource(res)) {
		(*resource)->type = res->type;
		(*resource)->length = sizeof(struct acpi_resource);
		(*resource)++;
	}

	return AE_OK;
}

int pnpacpi_build_resource_template(acpi_handle handle,
	struct acpi_buffer *buffer)
{
	struct acpi_resource *resource;
	int res_cnt = 0;
	acpi_status status;

	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
		pnpacpi_count_resources, &res_cnt);
	if (ACPI_FAILURE(status)) {
		pnp_err("Evaluate _CRS failed");
		return -EINVAL;
	}
	if (!res_cnt)
		return -EINVAL;
	buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1;
	buffer->pointer = kcalloc(1, buffer->length - 1, GFP_KERNEL);
	if (!buffer->pointer)
		return -ENOMEM;
	pnp_dbg("Res cnt %d", res_cnt);
	resource = (struct acpi_resource *)buffer->pointer;
	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
		pnpacpi_type_resources, &resource);
	if (ACPI_FAILURE(status)) {
		kfree(buffer->pointer);
		pnp_err("Evaluate _CRS failed");
		return -EINVAL;
	}
	/* resource will pointer the end resource now */
	resource->type = ACPI_RESOURCE_TYPE_END_TAG;

	return 0;
}

static void pnpacpi_encode_irq(struct acpi_resource *resource,
	struct resource *p)
{
	int triggering, polarity;

	decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
	resource->data.irq.triggering = triggering;
	resource->data.irq.polarity = polarity;
	if (triggering == ACPI_EDGE_SENSITIVE)
		resource->data.irq.sharable = ACPI_EXCLUSIVE;
	else
		resource->data.irq.sharable = ACPI_SHARED;
	resource->data.irq.interrupt_count = 1;
	resource->data.irq.interrupts[0] = p->start;
}

static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
	struct resource *p)
{
	int triggering, polarity;

	decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
	resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
	resource->data.extended_irq.triggering = triggering;
	resource->data.extended_irq.polarity = polarity;
	if (triggering == ACPI_EDGE_SENSITIVE)
		resource->data.irq.sharable = ACPI_EXCLUSIVE;
	else
		resource->data.irq.sharable = ACPI_SHARED;
	resource->data.extended_irq.interrupt_count = 1;
	resource->data.extended_irq.interrupts[0] = p->start;
}

static void pnpacpi_encode_dma(struct acpi_resource *resource,
	struct resource *p)
{
	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
	if (p->flags & IORESOURCE_DMA_COMPATIBLE)
		resource->data.dma.type = ACPI_COMPATIBILITY;
	else if (p->flags & IORESOURCE_DMA_TYPEA)
		resource->data.dma.type = ACPI_TYPE_A;
	else if (p->flags & IORESOURCE_DMA_TYPEB)
		resource->data.dma.type = ACPI_TYPE_B;
	else if (p->flags & IORESOURCE_DMA_TYPEF)
		resource->data.dma.type = ACPI_TYPE_F;
	if (p->flags & IORESOURCE_DMA_8BIT)
		resource->data.dma.transfer = ACPI_TRANSFER_8;
	else if (p->flags & IORESOURCE_DMA_8AND16BIT)
		resource->data.dma.transfer = ACPI_TRANSFER_8_16;
	else if (p->flags & IORESOURCE_DMA_16BIT)
		resource->data.dma.transfer = ACPI_TRANSFER_16;
	resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
	resource->data.dma.channel_count = 1;
	resource->data.dma.channels[0] = p->start;
}

static void pnpacpi_encode_io(struct acpi_resource *resource,
	struct resource *p)
{
	/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
	resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
		ACPI_DECODE_16 : ACPI_DECODE_10;
	resource->data.io.minimum = p->start;
	resource->data.io.maximum = p->end;
	resource->data.io.alignment = 0; /* Correct? */
	resource->data.io.address_length = p->end - p->start + 1;
}

static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
	struct resource *p)
{
	resource->data.fixed_io.address = p->start;
	resource->data.fixed_io.address_length = p->end - p->start + 1;
}

static void pnpacpi_encode_mem24(struct acpi_resource *resource,
	struct resource *p)
{
	/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
	resource->data.memory24.write_protect =
		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
	resource->data.memory24.minimum = p->start;
	resource->data.memory24.maximum = p->end;
	resource->data.memory24.alignment = 0;
	resource->data.memory24.address_length = p->end - p->start + 1;
}

static void pnpacpi_encode_mem32(struct acpi_resource *resource,
	struct resource *p)
{
	resource->data.memory32.write_protect =
		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
	resource->data.memory32.minimum = p->start;
	resource->data.memory32.maximum = p->end;
	resource->data.memory32.alignment = 0;
	resource->data.memory32.address_length = p->end - p->start + 1;
}

static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
	struct resource *p)
{
	resource->data.fixed_memory32.write_protect =
		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
	resource->data.fixed_memory32.address = p->start;
	resource->data.fixed_memory32.address_length = p->end - p->start + 1;
}

int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
	struct acpi_buffer *buffer)
{
	int i = 0;
	/* pnpacpi_build_resource_template allocates extra mem */
	int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
	struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
	int port = 0, irq = 0, dma = 0, mem = 0;

	pnp_dbg("res cnt %d", res_cnt);
	while (i < res_cnt) {
		switch(resource->type) {
		case ACPI_RESOURCE_TYPE_IRQ:
			pnp_dbg("Encode irq");
			pnpacpi_encode_irq(resource,
				&res_table->irq_resource[irq]);
			irq++;
			break;

		case ACPI_RESOURCE_TYPE_DMA:
			pnp_dbg("Encode dma");
			pnpacpi_encode_dma(resource,
				&res_table->dma_resource[dma]);
			dma++;
			break;
		case ACPI_RESOURCE_TYPE_IO:
			pnp_dbg("Encode io");
			pnpacpi_encode_io(resource,
				&res_table->port_resource[port]);
			port++;
			break;
		case ACPI_RESOURCE_TYPE_FIXED_IO:
			pnp_dbg("Encode fixed io");
			pnpacpi_encode_fixed_io(resource,
				&res_table->port_resource[port]);
			port++;
			break;
		case ACPI_RESOURCE_TYPE_MEMORY24:
			pnp_dbg("Encode mem24");
			pnpacpi_encode_mem24(resource,
				&res_table->mem_resource[mem]);
			mem++;
			break;
		case ACPI_RESOURCE_TYPE_MEMORY32:
			pnp_dbg("Encode mem32");
			pnpacpi_encode_mem32(resource,
				&res_table->mem_resource[mem]);
			mem++;
			break;
		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
			pnp_dbg("Encode fixed mem32");
			pnpacpi_encode_fixed_mem32(resource,
				&res_table->mem_resource[mem]);
			mem++;
			break;
		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
			pnp_dbg("Encode ext irq");
			pnpacpi_encode_ext_irq(resource,
				&res_table->irq_resource[irq]);
			irq++;
			break;
		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
		case ACPI_RESOURCE_TYPE_VENDOR:
		case ACPI_RESOURCE_TYPE_END_TAG:
		case ACPI_RESOURCE_TYPE_ADDRESS16:
		case ACPI_RESOURCE_TYPE_ADDRESS32:
		case ACPI_RESOURCE_TYPE_ADDRESS64:
		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
		default: /* other type */
			pnp_warn("unknown resource type %d", resource->type);
			return -EINVAL;
		}
		resource++;
		i++;
	}
	return 0;
}
Comment 16 CASTET Matthieu 2006-04-14 14:09:32 UTC
Created attachment 7874 [details]
correct resources printf

Could you retry the "for i in /sys/bus/pnp/devices/*; do echo $i; cat $i/id;
cat $i/resources; cat $i/options; done" on the -mm kernel with this patch ?
Comment 17 Bjorn Helgaas 2006-04-20 21:19:10 UTC
Created attachment 7930 [details]
2.6.17-rc1-mm3 debugging patch

This won't fix anything but will help us learn where the
problem is.

I built this against 2.6.17-rc1-mm3, but I think it will
apply fine to earlier -mm kernels.

I'm interested in the dmesg log.
Comment 18 CASTET Matthieu 2006-04-21 10:33:09 UTC
The problem is in PNP0A03 :
 WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
                    0x0000,             // Address Space Granularity
                    0x0000,             // Address Range Minimum
                    0x0CF7,             // Address Range Maximum
                    0x0000,             // Address Translation Offset
                    0x0CF8,             // Address Length
                    ,,, TypeStatic)
                WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode,
EntireRange,
                    0x0000,             // Address Space Granularity
                    0x0D00,             // Address Range Minimum
                    0xFFFF,             // Address Range Maximum
                    0x0000,             // Address Translation Offset
                    0xF300,             // Address Length
                    ,,, TypeStatic)

This WordIO were parsed as memory, now there are seen as io (as they should be).

0xd00-0xffff and 0x0-0xcf7 are reserved by this device.
The remaining IO region available for others devices are 0xcf8-0xd00.
But the sound card whant to take :
io 0x220-0x22f
io 0x388-0x38b
io 0x500-0x50f
and couldn't because it conflict with 0x0-0xcf7 io resource.

The problem only happen with the isa sound card and not with others device on
pnpacpi bus, because their resources is already allocated and the pnp core don't
check for conflict.

I don't know what is the PNP0A03 device, but we may be just blacklist it...

PS :
On my D1170 I have the same PNP0A03 device :
 cat /sys/bus/pnp/devices/00\:00/resources 
state = active
io 0x0-0xcf7
io 0xd00-0xffff
io 0xcf8-0xcff
mem 0xa0000-0xbffff
mem 0xc8000-0xdffff
mem 0x20000000-0xffb7ffff
mem 0xffb80000-0xffbfffff

Comment 19 CASTET Matthieu 2006-04-21 10:55:32 UTC
Created attachment 7931 [details]
balcklist pnp0a03 device

It is a quick fix to solve the problem.
Comment 20 CASTET Matthieu 2006-04-21 12:25:39 UTC
According to acpi spec [1], bus device set in their CRS the ressource for the
children.
Some macros have a ResourceUsage parameter[2]. If is set to ResourceProducer the
resource is for the children.

If we look the CRS of the PNP0A03, we have :
                WordBusNumber (ResourceConsumer
                WordIO (ResourceProducer
                WordIO (ResourceProducer
                DWordMemory (ResourceProducer
                DWordMemory (ResourceProducer
                DWordMemory (ResourceProducer
                IO (Decode16

Bingo, the large io range WordIO that cause the problem has the ResourceProducer
parameter.

I believe we should ignore ResourceProducer data.
What do you think ?

[1]
6.2.1 _CRS (Current Resource Settings)
This required object evaluates to a byte stream that describes the system
resources currently allocated to a
device. Additionally, a bus device must supply the resources that it decodes and
can assign to its children
devices.

[2]
ResourceUsage specifies whether the bus range is consumed by this device
(ResourceConsumer) or
passed on to child devices (ResourceProducer). If nothing is specified, then
ResourceConsumer is
assumed.
Comment 21 Bjorn Helgaas 2006-04-21 15:47:29 UTC
> Bingo, the large io range WordIO that cause the problem has the ResourceProducer
> parameter.
> 
> I believe we should ignore ResourceProducer data.
> What do you think ?

I think we already ignore the ResourceProducer flag.  The only places
ACPI_PRODUCER and ACPI_CONSUMER appear are in some IRQ and ia64 code.
Neither should be involved here.

The PNP0A03 device is a bridge, so isn't the firmware trying to tell
us that the ISA card is on the other side of the bridge?  Then it
would make sense that the bridge would have a ResourceProducer
region, part of which is passed on to the ISA card (a child).

Maybe /proc/ioports really should look like this, with all the
southbridge devices and the ISA sound card being nested under the
bridge:

  0000-0cf7 : PCI bridge
    0000-001f : dma1
    ...
    0500-050f : AD1816A
    ...
  0cf8-0cff : PCI conf1
  ...

I wonder if the problem is that PNP doesn't know how to deal with
a PNP device that is a bridge on the way to another PNP device.
I don't know a whole lot about PNP resource management, but the
__check_region() in pnp_check_port() and the lack of any
insert_resource() calls in drivers/pnp makes me think that nesting
PNP resources like this might not work.

Uwe, don't waste your time trying my patch (the 2.6.17-rc1-mm3
debugging patch).  I think Matthieu has put his finger on the
problem.  I'm sure his "blacklist PNP0A03 device" patch will
probably make your sound card work, but I don't think that's
really the best solution.

Comment 22 CASTET Matthieu 2006-04-23 03:46:20 UTC
> I wonder if the problem is that PNP doesn't know how to deal with
> a PNP device that is a bridge on the way to another PNP device.
Yes I believe it is the problem : pnp layer expect only consumer resource.

My idea was to add in pnpacpi_parse_allocated_address_space something like

if (p->producer_consumer == ACPI_PRODUCER)
 return;

in order it ignore ResourceProducer data (the same check should be added for
PRODUCER resources).

Of course extending pnp layer in order it support ResourceProducer data would be
great, but it will need more works.
Comment 23 Bjorn Helgaas 2006-04-23 21:10:25 UTC
> > I wonder if the problem is that PNP doesn't know how to deal with
> > a PNP device that is a bridge on the way to another PNP device.
> Yes I believe it is the problem : pnp layer expect only consumer resource.
> 
> My idea was to add in pnpacpi_parse_allocated_address_space something like
> 
> if (p->producer_consumer == ACPI_PRODUCER)
>  return;
> 
> in order it ignore ResourceProducer data (the same check should be added for
> PRODUCER resources).

Of course.  It finally dawned on me yesterday that this must be what
you meant.  It would be nice if PNP could deal with the bridge windows,
but your idea seems like a good interim fix.  

Comment 24 CASTET Matthieu 2006-06-10 14:21:05 UTC
Created attachment 8284 [details]
patch against 2.6.17-rc6-mm2 that should solve the problem
Comment 25 Bjorn Helgaas 2006-06-10 21:36:18 UTC
Thanks for doing this.  I actually *was* working on it, but spent 
a couple days resolving other issues that broke recent -mm kernels 
on my test machine. 
 
My patch was similar to yours, but I missed the Extended Address64 
case (which we don't do anything with yet anywawy) and the Extended 
IRQ descriptor. 
 
Do we need similar tests in pnpacpi_parse_address_option() 
and pnpacpi_option_resource()? 
 
Also, there's something I still don't understand: 
We think the conflict occurs because the sound card needs 
  io 0x220-0x22f 
but the PNP0A03 bridge has an 
  io 0x0-0xcf7 
resource.  But I don't see where that PNP0A03 resource is 
actually reserved.  I'm sure I just missed it.  Can you 
point out my error? 
 
Comment 26 Shaohua 2006-06-26 23:22:52 UTC
Hmm, we should blacklist pnp0a03 in pnp layer. It's the root bridge and 
shouldn't export to pnp layer to me. I remember it's blacklist in previous 
implementation.
Comment 27 Natalie Protasevich 2007-06-25 00:34:06 UTC
It looks like the patch is in; I suppose Uwe tested it (invisibly :) and the bug can be closed now?
Thanks!

Note You need to log in before you can comment on or make changes to this bug.