Commit b96ea616 authored by Michael Ellerman's avatar Michael Ellerman
Browse files

Merge VAS page fault handling into next

As described by Haren:

On Power9, Virtual Accelerator Switchboard (VAS) allows user space or
kernel to communicate with Nest Accelerator (NX) directly using
COPY/PASTE instructions. NX provides various functionalities such as
compression, encryption and etc. But only compression (842 and GZIP
formats) is supported in Linux kernel on power9.

842 compression driver (drivers/crypto/nx/nx-842-powernv.c) is already
included in Linux. Only GZIP support will be available from user
space.

Applications can issue GZIP compression / decompression requests to NX
with COPY/PASTE instructions. When NX is processing these requests,
can hit fault on the request buffer (not in memory). It issues an
interrupt and pastes fault CRB in fault FIFO. Expects kernel to handle
this fault and return credits for both send and fault windows after
processing.

This patch series adds IRQ and fault window setup, and NX fault
handling:
  - Alloc IRQ and trigger port address, and configure IRQ per VAS
    instance.
  - Set port# for each window to generate an interrupt when noticed
    fault.
  - Set fault window and FIFO on which NX paste fault CRB.
  - Setup IRQ thread fault handler per VAS instance.
  - When receiving an interrupt, Read CRBs from fault FIFO and update
    coprocessor_status_block (CSB) in the corresponding CRB with
    translation failure (CSB_CC_TRANSLATION). After issuing NX
    requests, process polls on CSB address. When it sees translation
    error, can touch the request buffer to bring the page in to memory
    and reissue NX request.
  - If copy_to_user fails on user space CSB address, OS sends SEGV
    signal.
parents ae83d0b4 c420644c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@ typedef struct {
	/* Number of users of the external (Nest) MMU */
	atomic_t copros;

	/* Number of user space windows opened in process mm_context */
	atomic_t vas_windows;

	struct hash_mm_context *hash_context;

	unsigned long vdso_base;
+18 −2
Original line number Diff line number Diff line
@@ -108,6 +108,17 @@ struct data_descriptor_entry {
	__be64 address;
} __packed __aligned(DDE_ALIGN);

/* 4.3.2 NX-stamped Fault CRB */

#define NX_STAMP_ALIGN          (0x10)

struct nx_fault_stamp {
	__be64 fault_storage_addr;
	__be16 reserved;
	__u8   flags;
	__u8   fault_status;
	__be32 pswid;
} __packed __aligned(NX_STAMP_ALIGN);

/* Chapter 6.5.2 Coprocessor-Request Block (CRB) */

@@ -135,10 +146,15 @@ struct coprocessor_request_block {

	struct coprocessor_completion_block ccb;

	u8 reserved[48];
	union {
		struct nx_fault_stamp nx;
		u8 reserved[16];
	} stamp;

	u8 reserved[32];

	struct coprocessor_status_block csb;
} __packed __aligned(CRB_ALIGN);
} __packed;


/* RFC02167 Initiate Coprocessor Instructions document
+30 −0
Original line number Diff line number Diff line
@@ -185,11 +185,41 @@ static inline void mm_context_remove_copro(struct mm_struct *mm)
			dec_mm_active_cpus(mm);
	}
}

/*
 * vas_windows counter shows number of open windows in the mm
 * context. During context switch, use this counter to clear the
 * foreign real address mapping (CP_ABORT) for the thread / process
 * that intend to use COPY/PASTE. When a process closes all windows,
 * disable CP_ABORT which is expensive to run.
 *
 * For user context, register a copro so that TLBIs are seen by the
 * nest MMU. mm_context_add/remove_vas_window() are used only for user
 * space windows.
 */
static inline void mm_context_add_vas_window(struct mm_struct *mm)
{
	atomic_inc(&mm->context.vas_windows);
	mm_context_add_copro(mm);
}

static inline void mm_context_remove_vas_window(struct mm_struct *mm)
{
	int v;

	mm_context_remove_copro(mm);
	v = atomic_dec_if_positive(&mm->context.vas_windows);

	/* Detect imbalance between add and remove */
	WARN_ON(v < 0);
}
#else
static inline void inc_mm_active_cpus(struct mm_struct *mm) { }
static inline void dec_mm_active_cpus(struct mm_struct *mm) { }
static inline void mm_context_add_copro(struct mm_struct *mm) { }
static inline void mm_context_remove_copro(struct mm_struct *mm) { }
static inline void mm_context_add_vas_windows(struct mm_struct *mm) { }
static inline void mm_context_remove_vas_windows(struct mm_struct *mm) { }
#endif


+0 −1
Original line number Diff line number Diff line
@@ -272,7 +272,6 @@ struct thread_struct {
	unsigned 	mmcr0;

	unsigned 	used_ebb;
	unsigned int	used_vas;
#endif
};

+0 −2
Original line number Diff line number Diff line
@@ -102,8 +102,6 @@ static inline void clear_task_ebb(struct task_struct *t)
#endif
}

extern int set_thread_uses_vas(void);

extern int set_thread_tidr(struct task_struct *t);

#endif /* _ASM_POWERPC_SWITCH_TO_H */
Loading