Skip to content

Commit

Permalink
[POWERPC] pasemi: Add workaround for erratum 5945
Browse files Browse the repository at this point in the history
Erratum 5945 causes some of the registers on the PCIe root ports to
not read correctly.  Do a small dance to avoid this: Write an unused
register, read the value and write it back.  Thankfully this is not in
a hot code path.

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Olof Johansson authored and Paul Mackerras committed Sep 13, 2007
1 parent 68c8404 commit 4d44233
Showing 1 changed file with 60 additions and 2 deletions.
62 changes: 60 additions & 2 deletions arch/powerpc/platforms/pasemi/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,61 @@ static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset);
}

static inline int is_root_port(int busno, int devfn)
{
return ((busno == 0) && (PCI_FUNC(devfn) < 4) &&
((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17)));
}

static inline int is_5945_reg(int reg)
{
return (((reg >= 0x18) && (reg < 0x34)) ||
((reg >= 0x158) && (reg < 0x178)));
}

static int workaround_5945(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
void volatile __iomem *addr, *dummy;
int byte;
u32 tmp;

if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset))
return 0;

hose = pci_bus_to_host(bus);

addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3);
byte = offset & 0x3;

/* Workaround bug 5945: write 0 to a dummy register before reading,
* and write back what we read. We must read/write the full 32-bit
* contents so we need to shift and mask by hand.
*/
dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10);
out_le32(dummy, 0);
tmp = in_le32(addr);
out_le32(addr, tmp);

switch (len) {
case 1:
*val = (tmp >> (8*byte)) & 0xff;
break;
case 2:
if (byte == 0)
*val = tmp & 0xffff;
else
*val = (tmp >> 16) & 0xffff;
break;
default:
*val = tmp;
break;
}

return 1;
}

static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
Expand All @@ -64,6 +119,9 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
if (!pa_pxp_offset_valid(bus->number, devfn, offset))
return PCIBIOS_BAD_REGISTER_NUMBER;

if (workaround_5945(bus, devfn, offset, len, val))
return PCIBIOS_SUCCESSFUL;

addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);

/*
Expand Down Expand Up @@ -180,7 +238,7 @@ void __iomem *pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset)
{
struct pci_controller *hose;

hose = pci_bus_to_host(bus);
hose = pci_bus_to_host(dev->bus);

return pa_pxp_cfg_addr(hose, hose->number, dev->devfn, int offset)
return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset);
}

0 comments on commit 4d44233

Please sign in to comment.