powerpc: Fix OF parsing of 64 bits PCI addresses
The OF parsing code for PCI addresses isn't always treating properly the address space indication 0b11 (ie. 0x3) as meaning 64 bits memory space. This means that it fails to parse addresses for PCI BARs that have this encoding set by the firmware, which happens on some SLOF versions and breaks offb palette handling on Powerstation. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
This commit is contained in:
parent
1856c02040
commit
67260ac9a3
2 changed files with 30 additions and 25 deletions
|
@ -598,6 +598,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
|||
res->start = pci_addr;
|
||||
break;
|
||||
case 2: /* PCI Memory space */
|
||||
case 3: /* PCI 64 bits Memory space */
|
||||
printk(KERN_INFO
|
||||
" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
|
||||
cpu_addr, cpu_addr + size - 1, pci_addr,
|
||||
|
|
|
@ -128,31 +128,6 @@ static void of_bus_pci_count_cells(struct device_node *np,
|
|||
*sizec = 2;
|
||||
}
|
||||
|
||||
static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
|
||||
{
|
||||
u64 cp, s, da;
|
||||
|
||||
/* Check address type match */
|
||||
if ((addr[0] ^ range[0]) & 0x03000000)
|
||||
return OF_BAD_ADDR;
|
||||
|
||||
/* Read address values, skipping high cell */
|
||||
cp = of_read_number(range + 1, na - 1);
|
||||
s = of_read_number(range + na + pna, ns);
|
||||
da = of_read_number(addr + 1, na - 1);
|
||||
|
||||
DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
|
||||
|
||||
if (da < cp || da >= (cp + s))
|
||||
return OF_BAD_ADDR;
|
||||
return da - cp;
|
||||
}
|
||||
|
||||
static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
|
||||
{
|
||||
return of_bus_default_translate(addr + 1, offset, na - 1);
|
||||
}
|
||||
|
||||
static unsigned int of_bus_pci_get_flags(const u32 *addr)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
|
@ -172,6 +147,35 @@ static unsigned int of_bus_pci_get_flags(const u32 *addr)
|
|||
return flags;
|
||||
}
|
||||
|
||||
static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
|
||||
{
|
||||
u64 cp, s, da;
|
||||
unsigned int af, rf;
|
||||
|
||||
af = of_bus_pci_get_flags(addr);
|
||||
rf = of_bus_pci_get_flags(range);
|
||||
|
||||
/* Check address type match */
|
||||
if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
|
||||
return OF_BAD_ADDR;
|
||||
|
||||
/* Read address values, skipping high cell */
|
||||
cp = of_read_number(range + 1, na - 1);
|
||||
s = of_read_number(range + na + pna, ns);
|
||||
da = of_read_number(addr + 1, na - 1);
|
||||
|
||||
DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
|
||||
|
||||
if (da < cp || da >= (cp + s))
|
||||
return OF_BAD_ADDR;
|
||||
return da - cp;
|
||||
}
|
||||
|
||||
static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
|
||||
{
|
||||
return of_bus_default_translate(addr + 1, offset, na - 1);
|
||||
}
|
||||
|
||||
const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
|
||||
unsigned int *flags)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue