Commit 1ab66d1f authored by Alistair Popple's avatar Alistair Popple Committed by Michael Ellerman

powerpc/powernv: Introduce address translation services for Nvlink2

Nvlink2 supports address translation services (ATS) allowing devices
to request address translations from an mmu known as the nest MMU
which is setup to walk the CPU page tables.

To access this functionality certain firmware calls are required to
setup and manage hardware context tables in the nvlink processing unit
(NPU). The NPU also manages forwarding of TLB invalidates (known as
address translation shootdowns/ATSDs) to attached devices.

This patch exports several methods to allow device drivers to register
a process id (PASID/PID) in the hardware tables and to receive
notification of when a device should stop issuing address translation
requests (ATRs). It also adds a fault handler to allow device drivers
to demand fault pages in.
Signed-off-by: default avatarAlistair Popple <alistair@popple.id.au>
[mpe: Fix up comment formatting, use flush_tlb_mm()]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 4c3b89ef
...@@ -75,10 +75,16 @@ extern struct patb_entry *partition_tb; ...@@ -75,10 +75,16 @@ extern struct patb_entry *partition_tb;
typedef unsigned long mm_context_id_t; typedef unsigned long mm_context_id_t;
struct spinlock; struct spinlock;
/* Maximum possible number of NPUs in a system. */
#define NV_MAX_NPUS 8
typedef struct { typedef struct {
mm_context_id_t id; mm_context_id_t id;
u16 user_psize; /* page size index */ u16 user_psize; /* page size index */
/* NPU NMMU context */
struct npu_context *npu_context;
#ifdef CONFIG_PPC_MM_SLICES #ifdef CONFIG_PPC_MM_SLICES
u64 low_slices_psize; /* SLB page size encodings */ u64 low_slices_psize; /* SLB page size encodings */
unsigned char high_slices_psize[SLICE_ARRAY_SIZE]; unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
......
...@@ -168,7 +168,10 @@ ...@@ -168,7 +168,10 @@
#define OPAL_INT_SET_MFRR 125 #define OPAL_INT_SET_MFRR 125
#define OPAL_PCI_TCE_KILL 126 #define OPAL_PCI_TCE_KILL 126
#define OPAL_NMMU_SET_PTCR 127 #define OPAL_NMMU_SET_PTCR 127
#define OPAL_LAST 127 #define OPAL_NPU_INIT_CONTEXT 146
#define OPAL_NPU_DESTROY_CONTEXT 147
#define OPAL_NPU_MAP_LPAR 148
#define OPAL_LAST 148
/* Device tree flags */ /* Device tree flags */
......
...@@ -29,6 +29,11 @@ extern struct device_node *opal_node; ...@@ -29,6 +29,11 @@ extern struct device_node *opal_node;
/* API functions */ /* API functions */
int64_t opal_invalid_call(void); int64_t opal_invalid_call(void);
int64_t opal_npu_destroy_context(uint64_t phb_id, uint64_t pid, uint64_t bdf);
int64_t opal_npu_init_context(uint64_t phb_id, int pasid, uint64_t msr,
uint64_t bdf);
int64_t opal_npu_map_lpar(uint64_t phb_id, uint64_t bdf, uint64_t lparid,
uint64_t lpcr);
int64_t opal_console_write(int64_t term_number, __be64 *length, int64_t opal_console_write(int64_t term_number, __be64 *length,
const uint8_t *buffer); const uint8_t *buffer);
int64_t opal_console_read(int64_t term_number, __be64 *length, int64_t opal_console_read(int64_t term_number, __be64 *length,
......
...@@ -11,9 +11,31 @@ ...@@ -11,9 +11,31 @@
#define _ASM_POWERNV_H #define _ASM_POWERNV_H
#ifdef CONFIG_PPC_POWERNV #ifdef CONFIG_PPC_POWERNV
#define NPU2_WRITE 1
extern void powernv_set_nmmu_ptcr(unsigned long ptcr); extern void powernv_set_nmmu_ptcr(unsigned long ptcr);
extern struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev,
unsigned long flags,
struct npu_context *(*cb)(struct npu_context *, void *),
void *priv);
extern void pnv_npu2_destroy_context(struct npu_context *context,
struct pci_dev *gpdev);
extern int pnv_npu2_handle_fault(struct npu_context *context, uintptr_t *ea,
unsigned long *flags, unsigned long *status,
int count);
#else #else
static inline void powernv_set_nmmu_ptcr(unsigned long ptcr) { } static inline void powernv_set_nmmu_ptcr(unsigned long ptcr) { }
static inline struct npu_context *pnv_npu2_init_context(struct pci_dev *gpdev,
unsigned long flags,
struct npu_context *(*cb)(struct npu_context *, void *),
void *priv) { return ERR_PTR(-ENODEV); }
static inline void pnv_npu2_destroy_context(struct npu_context *context,
struct pci_dev *gpdev) { }
static inline int pnv_npu2_handle_fault(struct npu_context *context,
uintptr_t *ea, unsigned long *flags,
unsigned long *status, int count) {
return -ENODEV;
}
#endif #endif
#endif /* _ASM_POWERNV_H */ #endif /* _ASM_POWERNV_H */
...@@ -138,6 +138,8 @@ static int radix__init_new_context(struct mm_struct *mm) ...@@ -138,6 +138,8 @@ static int radix__init_new_context(struct mm_struct *mm)
rts_field = radix__get_tree_size(); rts_field = radix__get_tree_size();
process_tb[index].prtb0 = cpu_to_be64(rts_field | __pa(mm->pgd) | RADIX_PGD_INDEX_SIZE); process_tb[index].prtb0 = cpu_to_be64(rts_field | __pa(mm->pgd) | RADIX_PGD_INDEX_SIZE);
mm->context.npu_context = NULL;
return index; return index;
} }
......
This diff is collapsed.
...@@ -292,3 +292,6 @@ OPAL_CALL(opal_int_eoi, OPAL_INT_EOI); ...@@ -292,3 +292,6 @@ OPAL_CALL(opal_int_eoi, OPAL_INT_EOI);
OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR); OPAL_CALL(opal_int_set_mfrr, OPAL_INT_SET_MFRR);
OPAL_CALL(opal_pci_tce_kill, OPAL_PCI_TCE_KILL); OPAL_CALL(opal_pci_tce_kill, OPAL_PCI_TCE_KILL);
OPAL_CALL(opal_nmmu_set_ptcr, OPAL_NMMU_SET_PTCR); OPAL_CALL(opal_nmmu_set_ptcr, OPAL_NMMU_SET_PTCR);
OPAL_CALL(opal_npu_init_context, OPAL_NPU_INIT_CONTEXT);
OPAL_CALL(opal_npu_destroy_context, OPAL_NPU_DESTROY_CONTEXT);
OPAL_CALL(opal_npu_map_lpar, OPAL_NPU_MAP_LPAR);
...@@ -1262,6 +1262,8 @@ static void pnv_pci_ioda_setup_PEs(void) ...@@ -1262,6 +1262,8 @@ static void pnv_pci_ioda_setup_PEs(void)
/* PE#0 is needed for error reporting */ /* PE#0 is needed for error reporting */
pnv_ioda_reserve_pe(phb, 0); pnv_ioda_reserve_pe(phb, 0);
pnv_ioda_setup_npu_PEs(hose->bus); pnv_ioda_setup_npu_PEs(hose->bus);
if (phb->model == PNV_PHB_MODEL_NPU2)
pnv_npu2_init(phb);
} }
} }
} }
......
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
struct pci_dn; struct pci_dn;
/* Maximum possible number of ATSD MMIO registers per NPU */
#define NV_NMMU_ATSD_REGS 8
enum pnv_phb_type { enum pnv_phb_type {
PNV_PHB_IODA1 = 0, PNV_PHB_IODA1 = 0,
PNV_PHB_IODA2 = 1, PNV_PHB_IODA2 = 1,
...@@ -174,6 +177,16 @@ struct pnv_phb { ...@@ -174,6 +177,16 @@ struct pnv_phb {
struct OpalIoP7IOCErrorData hub_diag; struct OpalIoP7IOCErrorData hub_diag;
} diag; } diag;
/* Nvlink2 data */
struct npu {
int index;
__be64 *mmio_atsd_regs[NV_NMMU_ATSD_REGS];
unsigned int mmio_atsd_count;
/* Bitmask for MMIO register usage */
unsigned long mmio_atsd_usage;
} npu;
#ifdef CONFIG_CXL_BASE #ifdef CONFIG_CXL_BASE
struct cxl_afu *cxl_afu; struct cxl_afu *cxl_afu;
#endif #endif
...@@ -236,7 +249,7 @@ extern long pnv_npu_set_window(struct pnv_ioda_pe *npe, int num, ...@@ -236,7 +249,7 @@ extern long pnv_npu_set_window(struct pnv_ioda_pe *npe, int num,
extern long pnv_npu_unset_window(struct pnv_ioda_pe *npe, int num); extern long pnv_npu_unset_window(struct pnv_ioda_pe *npe, int num);
extern void pnv_npu_take_ownership(struct pnv_ioda_pe *npe); extern void pnv_npu_take_ownership(struct pnv_ioda_pe *npe);
extern void pnv_npu_release_ownership(struct pnv_ioda_pe *npe); extern void pnv_npu_release_ownership(struct pnv_ioda_pe *npe);
extern int pnv_npu2_init(struct pnv_phb *phb);
/* cxl functions */ /* cxl functions */
extern bool pnv_cxl_enable_device_hook(struct pci_dev *dev); extern bool pnv_cxl_enable_device_hook(struct pci_dev *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment