Merge branch 'frankjpliu/master' into 'master' (merge request !61)

arm64: Work around Ampere Altra erratum #82288 PCIE_65
This commit is contained in:
leonylgao 2024-04-12 11:00:25 +00:00
commit 69591b8c51
6 changed files with 77 additions and 5 deletions

View File

@ -52,6 +52,9 @@ stable kernels.
| Allwinner | A64/R18 | UNKNOWN1 | SUN50I_ERRATUM_UNKNOWN1 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | Altra | #82288 | ALTRA_ERRATUM_82288 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne | AC03_CPU_38 | AMPERE_ERRATUM_AC03_CPU_38 |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+

View File

@ -439,6 +439,27 @@ config AMPERE_ERRATUM_AC03_CPU_38
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 interfaces 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

View File

@ -16,6 +16,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_can_pci_mmap_wc() 1
/* Generic PCI */

View File

@ -230,11 +230,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));
@ -581,6 +576,27 @@ static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
__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,

View File

@ -6243,3 +6243,12 @@ static void pci_fixup_d3cold_delay_1sec(struct pci_dev *pdev)
pdev->d3cold_delay = 1000;
}
DECLARE_PCI_FIXUP_FINAL(0x5555, 0x0004, pci_fixup_d3cold_delay_1sec);
#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

View File

@ -11,6 +11,21 @@
#include <linux/io.h>
#include <linux/export.h>
#include <linux/ioremap.h>
#include <linux/pgtable.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
void __iomem *generic_ioremap_prot(phys_addr_t phys_addr, size_t size,
pgprot_t prot)
@ -40,6 +55,10 @@ void __iomem *generic_ioremap_prot(phys_addr_t phys_addr, size_t size,
vaddr = (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
if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
free_vm_area(area);
return NULL;