Skip to content

Commit

Permalink
ampere/arm64: Work around Ampere Altra erratum #82288 PCIE_65
Browse files Browse the repository at this point in the history
Altra's PCIe controller may generate incorrect addresses when receiving
writes from the CPU with a discontiguous set of byte enables. Attempt to
work around this by handing out Device-nGnRE maps instead of Normal
Non-cacheable maps for PCIe memory areas.

Signed-off-by: D Scott Phillips <scott@os.amperecomputing.com>
  • Loading branch information
wangfuhai700 authored and kaixuxiakx committed Jul 12, 2021
1 parent 1e236c7 commit f454797
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Documentation/arm64/silicon-errata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ stable kernels.
| Allwinner | A64/R18 | UNKNOWN1 | SUN50I_ERRATUM_UNKNOWN1 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | Altra | #82288 | ALTRA_ERRATUM_82288 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 |
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 |
Expand Down
21 changes: 21 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,27 @@ menu "ARM errata workarounds via the alternatives framework"
config ARM64_WORKAROUND_CLEAN_CACHE
bool

config ALTRA_ERRATUM_82288
bool "Ampere Altra: 82288: PCIE_65: PCIe Root Port outbound write combining issue"
default y
help
This option adds an alternative code sequence to work around
Ampere Altra erratum 82288.

PCIe device drivers may map MMIO space as Normal, non-cacheable
memory attribute (e.g. Linux kernel drivers mapping MMIO
using ioremap_wc). This may be for the purpose of enabling write
combining or unaligned accesses. This can result in data corruption
on the PCIe interface’s outbound MMIO writes due to issues with the
write-combining operation.

The workaround modifies software that maps PCIe MMIO space as Normal,
non-cacheable memory (e.g. ioremap_wc) to instead Device,
non-gatheringmemory (e.g. ioremap). And all memory operations on PCIe
MMIO space must be strictly aligned.

If unsure, say Y.

config ARM64_ERRATUM_826319
bool "Cortex-A53: 826319: System might deadlock if a write cannot complete until read data is accepted"
default y
Expand Down
4 changes: 4 additions & 0 deletions arch/arm64/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
#define pcibios_assign_all_busses() \
(pci_has_flag(PCI_REASSIGN_ALL_BUS))

#ifdef CONFIG_ALTRA_ERRATUM_82288
extern bool __read_mostly have_altra_erratum_82288;
#endif

#define ARCH_GENERIC_PCI_MMAP_RESOURCE 1

extern int isa_dma_bridge_buggy;
Expand Down
26 changes: 21 additions & 5 deletions arch/arm64/include/asm/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,6 @@ static inline pte_t pte_mkyoung(pte_t pte)
return set_pte_bit(pte, __pgprot(PTE_AF));
}

static inline pte_t pte_mkspecial(pte_t pte)
{
return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
}

static inline pte_t pte_mkcont(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_CONT));
Expand Down Expand Up @@ -436,6 +431,27 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
__pgprot_modify(prot, PTE_ATTRINDX_MASK, \
PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)

#ifdef CONFIG_ALTRA_ERRATUM_82288
extern bool have_altra_erratum_82288;
#endif

static inline pte_t pte_mkspecial(pte_t pte)
{
#ifdef CONFIG_ALTRA_ERRATUM_82288
phys_addr_t phys = __pte_to_phys(pte);
pgprot_t prot = __pgprot(pte_val(pte) & ~PTE_ADDR_MASK);

if (unlikely(have_altra_erratum_82288) &&
(phys < 0x80000000 ||
(phys >= 0x200000000000 && phys < 0x400000000000) ||
(phys >= 0x600000000000 && phys < 0x800000000000))) {
pte = __pte(__phys_to_pte_val(phys) | pgprot_val(pgprot_device(prot)));
}
#endif

return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
}

#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
Expand Down
19 changes: 19 additions & 0 deletions arch/arm64/mm/ioremap.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@
#include <asm/tlbflush.h>
#include <asm/pgalloc.h>

#ifdef CONFIG_ALTRA_ERRATUM_82288
bool have_altra_erratum_82288 __read_mostly;
EXPORT_SYMBOL(have_altra_erratum_82288);

static bool is_altra_pci(phys_addr_t phys_addr, size_t size)
{
phys_addr_t end = phys_addr + size;

return (phys_addr < 0x80000000 ||
(end > 0x200000000000 && phys_addr < 0x400000000000) ||
(end > 0x600000000000 && phys_addr < 0x800000000000));
}
#endif

static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
pgprot_t prot, void *caller)
{
Expand Down Expand Up @@ -53,6 +67,11 @@ static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
addr = (unsigned long)area->addr;
area->phys_addr = phys_addr;

#ifdef CONFIG_ALTRA_ERRATUM_82288
if (unlikely(have_altra_erratum_82288 && is_altra_pci(phys_addr, size)))
prot = pgprot_device(prot);
#endif

err = ioremap_page_range(addr, addr + size, phys_addr, prot);
if (err) {
vunmap((void *)addr);
Expand Down
9 changes: 9 additions & 0 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -5618,3 +5618,12 @@ static void apex_pci_fixup_class(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_CLASS_HEADER(0x1ac1, 0x089a,
PCI_CLASS_NOT_DEFINED, 8, apex_pci_fixup_class);

#ifdef CONFIG_ALTRA_ERRATUM_82288
static void quirk_altra_erratum_82288(struct pci_dev *dev)
{
pr_info_once("Write combining PCI maps disabled due to hardware erratum\n");
have_altra_erratum_82288 = true;
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_AMPERE, 0xe100, quirk_altra_erratum_82288);
#endif

0 comments on commit f454797

Please sign in to comment.