lib: Flush everything when remote TLB flush range is too large

On latest Linux kernel (i.e. 5.2-rc1), we get large TLB flush
request for user space addresses (typically, start=x and end=-1).
This is caused by Linux kernel commit a21344dfc6 ("riscv: fix
sbi_remote_sfence_vma{,_asid}").

It's not practical to execute large number of sfence instructions
for a large TLB flush range because it takes too much time and
eventually causes CPU stall in Linux kernel.

This patch addresses above issue by upgrading TLB flush range to
TLB flush all whenever TLB flush range is greater than 1GB.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
This commit is contained in:
Anup Patel 2019-05-20 11:20:53 +05:30 committed by Anup Patel
parent 392749f633
commit 4e2cd47820
2 changed files with 18 additions and 4 deletions

View File

@ -31,7 +31,9 @@
#define PAGE_SHIFT (12)
#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
#define SBI_TLB_FLUSH_ALL ((unsigned long)-1)
#define SBI_TLB_FLUSH_MAX_SIZE (1UL << 30)
#define REG_L __REG_SEL(ld, lw)
#define REG_S __REG_SEL(sd, sw)

View File

@ -23,8 +23,8 @@
static inline int __sbi_tlb_fifo_range_check(struct sbi_tlb_info *curr,
struct sbi_tlb_info *next)
{
int curr_end;
int next_end;
unsigned long curr_end;
unsigned long next_end;
int ret = SBI_FIFO_UNCHANGED;
if (!curr || !next)
@ -91,17 +91,29 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event,
struct sbi_scratch *remote_scratch = NULL;
const struct sbi_platform *plat = sbi_platform_ptr(scratch);
struct sbi_fifo *ipi_tlb_fifo;
struct sbi_tlb_info *tinfo = data;
int ret = SBI_FIFO_UNCHANGED;
if (sbi_platform_hart_disabled(plat, hartid))
return -1;
/* Set IPI type on remote hart's scratch area and
/*
* Set IPI type on remote hart's scratch area and
* trigger the interrupt
*/
remote_scratch = sbi_hart_id_to_scratch(scratch, hartid);
if (event == SBI_IPI_EVENT_SFENCE_VMA ||
event == SBI_IPI_EVENT_SFENCE_VMA_ASID) {
/*
* If address range to flush is too big then simply
* upgrade it to flush all because we can only flush
* 4KB at a time.
*/
if (tinfo->size >= SBI_TLB_FLUSH_MAX_SIZE) {
tinfo->start = 0;
tinfo->size = SBI_TLB_FLUSH_ALL;
}
ipi_tlb_fifo = sbi_tlb_fifo_head_ptr(remote_scratch);
ret = sbi_fifo_inplace_update(ipi_tlb_fifo, data,
sbi_tlb_fifo_update_cb);