k1: support user-space load and store misaligned on io memory area
The PCIe BAR area must be mapped as IO attribute for GPU VRAM area, but, there may be some misaligned access in user-space program. Then, it will trigger 5# exception when misaligned load and 7# excepiton when misaligned store. And user-space program will crash because of the 5# exception and 7# exception can't be fixed. So, we try to process the user-space io area misligned access firstly when the 5# exception and 7# exception are caught Change-Id: Iac78bcdb8505dd113dcc4deed782e78016ddbf9b
This commit is contained in:
@@ -176,6 +176,19 @@ config SPACEMIT_ERRATA_LOAD_ATOMIC
|
||||
help
|
||||
This enable fix errata caused by readforward and writeback.
|
||||
|
||||
config SPACEMIT_K1_PCIE_USR_MISALIGNED
|
||||
bool "process user space misaligned access on PCIe Slave IO Area"
|
||||
depends on SOC_SPACEMIT_K1X
|
||||
default y
|
||||
help
|
||||
The PCIe controller in Spacemit K1 does not support discontinuous
|
||||
write operations with AXI bus-generated wstrb signals. Consequently,
|
||||
the PCIe slave memory space is mapped as IO attributes. However,
|
||||
when user-space programs perform unaligned memory accesses in this
|
||||
IO-attributed space, memory access faults occur. Specialized handling
|
||||
for this specific error type is implemented to ensure proper execution
|
||||
of user-space programs.
|
||||
|
||||
endif
|
||||
|
||||
endmenu # "SoC selection"
|
||||
|
||||
@@ -211,8 +211,63 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPACEMIT_K1_PCIE_USR_MISALIGNED
|
||||
|
||||
#define SPACEMIT_K1_PCIE_DATA_LOW (0x80000000)
|
||||
#define SPACEMIT_K1_PCIE_DATA_HIGH (0xB7FFFFFF)
|
||||
|
||||
static int check_if_user_io_area_misaligned(struct pt_regs *regs)
|
||||
{
|
||||
pte_t *ptep;
|
||||
spinlock_t *ptl;
|
||||
unsigned long v_addr = regs->badaddr, phy_addr;
|
||||
struct mm_struct *mm = current->mm;
|
||||
|
||||
/* try to get the pte of the trap address */
|
||||
ptep = get_locked_pte(mm, v_addr, &ptl);
|
||||
if (!ptep)
|
||||
return 0;
|
||||
|
||||
/* check if the area is _PAGE_IO attribute */
|
||||
if (!pte_present(*ptep) || !(pte_val(*ptep) & _PAGE_IO)) {
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* release the pte */
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
|
||||
/* check if the area is in pcie memory area */
|
||||
phy_addr = (pte_pfn(*ptep) << PAGE_SHIFT) | (v_addr & ~PAGE_MASK);
|
||||
if ((phy_addr < SPACEMIT_K1_PCIE_DATA_LOW) || (phy_addr > SPACEMIT_K1_PCIE_DATA_HIGH)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
DO_ERROR_INFO(do_trap_load_fault_inner,
|
||||
SIGSEGV, SEGV_ACCERR, "load access fault");
|
||||
asmlinkage __visible __trap_section void do_trap_load_fault(struct pt_regs *regs)
|
||||
{
|
||||
/* Try to process the exception as a load misaligned on io memory area */
|
||||
if (user_mode(regs)) {
|
||||
irqentry_enter_from_user_mode(regs);
|
||||
|
||||
if (check_if_user_io_area_misaligned(regs) && !handle_misaligned_load(regs)) {
|
||||
irqentry_exit_to_user_mode(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
irqentry_exit_to_user_mode(regs);
|
||||
}
|
||||
|
||||
do_trap_load_fault_inner(regs);
|
||||
}
|
||||
#else
|
||||
DO_ERROR_INFO(do_trap_load_fault,
|
||||
SIGSEGV, SEGV_ACCERR, "load access fault");
|
||||
#endif
|
||||
|
||||
asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
|
||||
{
|
||||
@@ -255,8 +310,31 @@ asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs
|
||||
irqentry_nmi_exit(regs, state);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPACEMIT_K1_PCIE_USR_MISALIGNED
|
||||
DO_ERROR_INFO(do_trap_store_fault_inner,
|
||||
SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
|
||||
asmlinkage __visible __trap_section void do_trap_store_fault(struct pt_regs *regs)
|
||||
{
|
||||
/* Try to process the exception as a store misaligned on io memory area */
|
||||
if (user_mode(regs)) {
|
||||
irqentry_enter_from_user_mode(regs);
|
||||
|
||||
if (check_if_user_io_area_misaligned(regs) && !handle_misaligned_store(regs)) {
|
||||
irqentry_exit_to_user_mode(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
irqentry_exit_to_user_mode(regs);
|
||||
}
|
||||
|
||||
do_trap_store_fault_inner(regs);
|
||||
}
|
||||
#else
|
||||
DO_ERROR_INFO(do_trap_store_fault,
|
||||
SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
|
||||
#endif
|
||||
|
||||
DO_ERROR_INFO(do_trap_ecall_s,
|
||||
SIGILL, ILL_ILLTRP, "environment call from S-mode");
|
||||
DO_ERROR_INFO(do_trap_ecall_m,
|
||||
|
||||
Reference in New Issue
Block a user