[ACPI] PNPACPI IRQ workaround for HP workstations
Move pcibios_penalize_isa_irq() to pnpacpi_parse_allocated_irqresource(). Previously we passed the GSI, not the IRQ, and we did it even if parsing the IRQ resource failed. Parse IRQ descriptors that contain multiple interrupts. This violates the spec (in _CRS, only one interrupt per descriptor is allowed), but some firmware, e.g., HP rx7620 and rx8620 descriptions of HPET, has this bug. Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Cc: Adam Belay <ambx1@neo.rr.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
5f0110f2a7
commit
dbed12da5b
@ -73,25 +73,35 @@ static void decode_irq_flags(int flag, int *edge_level, int *active_high_low)
|
||||
}
|
||||
|
||||
static void
|
||||
pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
|
||||
pnpacpi_parse_allocated_irqresource(struct pnp_resource_table * res, u32 gsi,
|
||||
int edge_level, int active_high_low)
|
||||
{
|
||||
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) {
|
||||
res->irq_resource[i].flags = IORESOURCE_IRQ; //Also clears _UNSET flag
|
||||
if (irq < 0) {
|
||||
res->irq_resource[i].flags |= IORESOURCE_DISABLED;
|
||||
return;
|
||||
}
|
||||
res->irq_resource[i].start =(unsigned long) irq;
|
||||
res->irq_resource[i].end = (unsigned long) irq;
|
||||
if (i >= PNP_MAX_IRQ)
|
||||
return;
|
||||
|
||||
res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
|
||||
irq = acpi_register_gsi(gsi, edge_level, active_high_low);
|
||||
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, int dma)
|
||||
pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, u32 dma)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < PNP_MAX_DMA &&
|
||||
@ -103,14 +113,14 @@ pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
|
||||
res->dma_resource[i].flags |= IORESOURCE_DISABLED;
|
||||
return;
|
||||
}
|
||||
res->dma_resource[i].start =(unsigned long) dma;
|
||||
res->dma_resource[i].end = (unsigned long) dma;
|
||||
res->dma_resource[i].start = dma;
|
||||
res->dma_resource[i].end = dma;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
|
||||
int io, int len)
|
||||
u32 io, u32 len)
|
||||
{
|
||||
int i = 0;
|
||||
while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
|
||||
@ -122,14 +132,14 @@ pnpacpi_parse_allocated_ioresource(struct pnp_resource_table * res,
|
||||
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);
|
||||
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,
|
||||
int mem, int len)
|
||||
u64 mem, u64 len)
|
||||
{
|
||||
int i = 0;
|
||||
while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
|
||||
@ -141,8 +151,8 @@ pnpacpi_parse_allocated_memresource(struct pnp_resource_table * res,
|
||||
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);
|
||||
res->mem_resource[i].start = mem;
|
||||
res->mem_resource[i].end = mem + len - 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,27 +161,28 @@ 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->id) {
|
||||
case ACPI_RSTYPE_IRQ:
|
||||
if ((res->data.irq.number_of_interrupts > 0) &&
|
||||
valid_IRQ(res->data.irq.interrupts[0])) {
|
||||
pnpacpi_parse_allocated_irqresource(res_table,
|
||||
acpi_register_gsi(res->data.irq.interrupts[0],
|
||||
res->data.irq.edge_level,
|
||||
res->data.irq.active_high_low));
|
||||
pcibios_penalize_isa_irq(res->data.irq.interrupts[0], 1);
|
||||
/*
|
||||
* 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.number_of_interrupts; i++) {
|
||||
pnpacpi_parse_allocated_irqresource(res_table,
|
||||
res->data.irq.interrupts[i],
|
||||
res->data.irq.edge_level,
|
||||
res->data.irq.active_high_low);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_RSTYPE_EXT_IRQ:
|
||||
if ((res->data.extended_irq.number_of_interrupts > 0) &&
|
||||
valid_IRQ(res->data.extended_irq.interrupts[0])) {
|
||||
pnpacpi_parse_allocated_irqresource(res_table,
|
||||
acpi_register_gsi(res->data.extended_irq.interrupts[0],
|
||||
res->data.extended_irq.edge_level,
|
||||
res->data.extended_irq.active_high_low));
|
||||
pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0], 1);
|
||||
for (i = 0; i < res->data.extended_irq.number_of_interrupts; i++) {
|
||||
pnpacpi_parse_allocated_irqresource(res_table,
|
||||
res->data.extended_irq.interrupts[i],
|
||||
res->data.extended_irq.edge_level,
|
||||
res->data.extended_irq.active_high_low);
|
||||
}
|
||||
break;
|
||||
case ACPI_RSTYPE_DMA:
|
||||
|
Loading…
Reference in New Issue
Block a user