Message ID | 1490714052-18902-8-git-send-email-clombard@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | Changes Requested |
Headers | show |
Le 28/03/2017 à 17:14, Christophe Lombard a écrit : > The new Coherent Accelerator Interface Architecture, level 2, for the > IBM POWER9 brings new content and features: > - POWER9 Service Layer > - Registers > - Radix mode > - Process element entry > - Dedicated-Shared Process Programming Model > - Translation Fault Handling > - CAPP > - Memory Context ID > If a valid mm_struct is found the memory context id is used for each > transaction associated with the process handle. The PSL uses the > context ID to find the corresponding process element. > > Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> > --- > drivers/misc/cxl/context.c | 16 ++- > drivers/misc/cxl/cxl.h | 137 +++++++++++++++++++++---- > drivers/misc/cxl/debugfs.c | 19 ++++ > drivers/misc/cxl/fault.c | 78 ++++++++------ > drivers/misc/cxl/guest.c | 8 +- > drivers/misc/cxl/irq.c | 53 ++++++++++ > drivers/misc/cxl/native.c | 247 ++++++++++++++++++++++++++++++++++++++++----- > drivers/misc/cxl/pci.c | 246 +++++++++++++++++++++++++++++++++++++++++--- > drivers/misc/cxl/trace.h | 43 ++++++++ > 9 files changed, 752 insertions(+), 95 deletions(-) > > diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c > index ac2531e..45363be 100644 > --- a/drivers/misc/cxl/context.c > +++ b/drivers/misc/cxl/context.c > @@ -188,12 +188,24 @@ int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma) > if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { > if (start + len > ctx->afu->adapter->ps_size) > return -EINVAL; > + > + if (cxl_is_psl9(ctx->afu)) { > + /* make sure there is a valid problem state > + * area space for this AFU > + */ > + if (ctx->master && !ctx->afu->psa) { > + pr_devel("AFU doesn't support mmio space\n"); > + return -EINVAL; > + } > + > + /* Can't mmap until the AFU is enabled */ > + if (!ctx->afu->enabled) > + return -EBUSY; > + } > } else { > if (start + len > ctx->psn_size) > return -EINVAL; > - } > > - if (ctx->afu->current_mode != CXL_MODE_DEDICATED) { > /* make sure there is a valid per process space for this AFU */ > if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) { > pr_devel("AFU doesn't support mmio space\n"); > diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h > index 2f2d9e4..aac0504 100644 > --- a/drivers/misc/cxl/cxl.h > +++ b/drivers/misc/cxl/cxl.h > @@ -63,7 +63,7 @@ typedef struct { > /* Memory maps. Ref CXL Appendix A */ > > /* PSL Privilege 1 Memory Map */ > -/* Configuration and Control area */ > +/* Configuration and Control area - CAIA 1&2 */ > static const cxl_p1_reg_t CXL_PSL_CtxTime = {0x0000}; > static const cxl_p1_reg_t CXL_PSL_ErrIVTE = {0x0008}; > static const cxl_p1_reg_t CXL_PSL_KEY1 = {0x0010}; > @@ -98,11 +98,29 @@ static const cxl_p1_reg_t CXL_XSL_Timebase = {0x0100}; > static const cxl_p1_reg_t CXL_XSL_TB_CTLSTAT = {0x0108}; > static const cxl_p1_reg_t CXL_XSL_FEC = {0x0158}; > static const cxl_p1_reg_t CXL_XSL_DSNCTL = {0x0168}; > +/* PSL registers - CAIA 2 */ > +static const cxl_p1_reg_t CXL_PSL9_CONTROL = {0x0020}; > +static const cxl_p1_reg_t CXL_XSL9_DSNCTL = {0x0168}; > +static const cxl_p1_reg_t CXL_PSL9_FIR1 = {0x0300}; > +static const cxl_p1_reg_t CXL_PSL9_FIR2 = {0x0308}; > +static const cxl_p1_reg_t CXL_PSL9_Timebase = {0x0310}; > +static const cxl_p1_reg_t CXL_PSL9_DEBUG = {0x0320}; > +static const cxl_p1_reg_t CXL_PSL9_FIR_CNTL = {0x0348}; > +static const cxl_p1_reg_t CXL_PSL9_DSNDCTL = {0x0350}; > +static const cxl_p1_reg_t CXL_PSL9_TB_CTLSTAT = {0x0340}; > +static const cxl_p1_reg_t CXL_PSL9_TRACECFG = {0x0368}; > +static const cxl_p1_reg_t CXL_PSL9_APCDEDALLOC = {0x0378}; > +static const cxl_p1_reg_t CXL_PSL9_APCDEDTYPE = {0x0380}; > +static const cxl_p1_reg_t CXL_PSL9_TNR_ADDR = {0x0388}; > +static const cxl_p1_reg_t CXL_PSL9_GP_CT = {0x0398}; > +static const cxl_p1_reg_t CXL_XSL9_IERAT = {0x0588}; > +static const cxl_p1_reg_t CXL_XSL9_ILPP = {0x0590}; > + > /* 0x7F00:7FFF Reserved PCIe MSI-X Pending Bit Array area */ > /* 0x8000:FFFF Reserved PCIe MSI-X Table Area */ > > /* PSL Slice Privilege 1 Memory Map */ > -/* Configuration Area */ > +/* Configuration Area - CAIA 1&2 */ > static const cxl_p1n_reg_t CXL_PSL_SR_An = {0x00}; > static const cxl_p1n_reg_t CXL_PSL_LPID_An = {0x08}; > static const cxl_p1n_reg_t CXL_PSL_AMBAR_An = {0x10}; > @@ -111,17 +129,18 @@ static const cxl_p1n_reg_t CXL_PSL_ID_An = {0x20}; > static const cxl_p1n_reg_t CXL_PSL_SERR_An = {0x28}; > /* Memory Management and Lookaside Buffer Management - CAIA 1*/ > static const cxl_p1n_reg_t CXL_PSL_SDR_An = {0x30}; > +/* Memory Management and Lookaside Buffer Management - CAIA 1&2 */ > static const cxl_p1n_reg_t CXL_PSL_AMOR_An = {0x38}; > -/* Pointer Area */ > +/* Pointer Area - CAIA 1&2 */ > static const cxl_p1n_reg_t CXL_HAURP_An = {0x80}; > static const cxl_p1n_reg_t CXL_PSL_SPAP_An = {0x88}; > static const cxl_p1n_reg_t CXL_PSL_LLCMD_An = {0x90}; > -/* Control Area */ > +/* Control Area - CAIA 1&2 */ > static const cxl_p1n_reg_t CXL_PSL_SCNTL_An = {0xA0}; > static const cxl_p1n_reg_t CXL_PSL_CtxTime_An = {0xA8}; > static const cxl_p1n_reg_t CXL_PSL_IVTE_Offset_An = {0xB0}; > static const cxl_p1n_reg_t CXL_PSL_IVTE_Limit_An = {0xB8}; > -/* 0xC0:FF Implementation Dependent Area */ > +/* 0xC0:FF Implementation Dependent Area - CAIA 1&2 */ > static const cxl_p1n_reg_t CXL_PSL_FIR_SLICE_An = {0xC0}; > static const cxl_p1n_reg_t CXL_AFU_DEBUG_An = {0xC8}; > /* 0xC0:FF Implementation Dependent Area - CAIA 1 */ > @@ -131,7 +150,7 @@ static const cxl_p1n_reg_t CXL_PSL_RXCTL_A = {0xE0}; > static const cxl_p1n_reg_t CXL_PSL_SLICE_TRACE = {0xE8}; > > /* PSL Slice Privilege 2 Memory Map */ > -/* Configuration and Control Area */ > +/* Configuration and Control Area - CAIA 1&2 */ > static const cxl_p2n_reg_t CXL_PSL_PID_TID_An = {0x000}; > static const cxl_p2n_reg_t CXL_CSRP_An = {0x008}; > /* Configuration and Control Area - CAIA 1 */ > @@ -145,17 +164,17 @@ static const cxl_p2n_reg_t CXL_PSL_AMR_An = {0x030}; > static const cxl_p2n_reg_t CXL_SLBIE_An = {0x040}; > static const cxl_p2n_reg_t CXL_SLBIA_An = {0x048}; > static const cxl_p2n_reg_t CXL_SLBI_Select_An = {0x050}; > -/* Interrupt Registers */ > +/* Interrupt Registers - CAIA 1&2 */ > static const cxl_p2n_reg_t CXL_PSL_DSISR_An = {0x060}; > static const cxl_p2n_reg_t CXL_PSL_DAR_An = {0x068}; > static const cxl_p2n_reg_t CXL_PSL_DSR_An = {0x070}; > static const cxl_p2n_reg_t CXL_PSL_TFC_An = {0x078}; > static const cxl_p2n_reg_t CXL_PSL_PEHandle_An = {0x080}; > static const cxl_p2n_reg_t CXL_PSL_ErrStat_An = {0x088}; > -/* AFU Registers */ > +/* AFU Registers - CAIA 1&2 */ > static const cxl_p2n_reg_t CXL_AFU_Cntl_An = {0x090}; > static const cxl_p2n_reg_t CXL_AFU_ERR_An = {0x098}; > -/* Work Element Descriptor */ > +/* Work Element Descriptor - CAIA 1&2 */ > static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; > /* 0x0C0:FFF Implementation Dependent Area */ > > @@ -182,6 +201,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; > #define CXL_PSL_SR_An_SF MSR_SF /* 64bit */ > #define CXL_PSL_SR_An_TA (1ull << (63-1)) /* Tags active, GA1: 0 */ > #define CXL_PSL_SR_An_HV MSR_HV /* Hypervisor, GA1: 0 */ > +#define CXL_PSL_SR_An_XLAT_hpt (0ull << (63-6))/* Hashed page table (HPT) mode */ > +#define CXL_PSL_SR_An_XLAT_roh (2ull << (63-6))/* Radix on HPT mode */ > +#define CXL_PSL_SR_An_XLAT_ror (3ull << (63-6))/* Radix on Radix mode */ > +#define CXL_PSL_SR_An_BOT (1ull << (63-10)) /* Use the in-memory segment table */ > #define CXL_PSL_SR_An_PR MSR_PR /* Problem state, GA1: 1 */ > #define CXL_PSL_SR_An_ISL (1ull << (63-53)) /* Ignore Segment Large Page */ > #define CXL_PSL_SR_An_TC (1ull << (63-54)) /* Page Table secondary hash */ > @@ -298,12 +321,38 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; > #define CXL_PSL_DSISR_An_S DSISR_ISSTORE /* Access was afu_wr or afu_zero */ > #define CXL_PSL_DSISR_An_K DSISR_KEYFAULT /* Access not permitted by virtual page class key protection */ > > +/****** CXL_PSL_DSISR_An - CAIA 2 ****************************************************/ > +#define CXL_PSL9_DSISR_An_TF (1ull << (63-3)) /* Translation fault */ > +#define CXL_PSL9_DSISR_An_PE (1ull << (63-4)) /* PSL Error (implementation specific) */ > +#define CXL_PSL9_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ > +#define CXL_PSL9_DSISR_An_OC (1ull << (63-6)) /* OS Context Warning */ > +#define CXL_PSL9_DSISR_An_S (1ull << (63-38)) /* TF for a write operation */ > +#define CXL_PSL9_DSISR_PENDING (CXL_PSL9_DSISR_An_TF | CXL_PSL9_DSISR_An_PE | CXL_PSL9_DSISR_An_AE | CXL_PSL9_DSISR_An_OC) > +/* NOTE: Bits 56:63 (Checkout Response Status) are valid when DSISR_An[TF] = 1 > + * Status (0:7) Encoding > + */ > +#define CXL_PSL9_DSISR_An_CO_MASK 0x00000000000000ffULL > +#define CXL_PSL9_DSISR_An_SF 0x0000000000000080ULL /* Segment Fault 0b10000000 */ > +#define CXL_PSL9_DSISR_An_PF_SLR 0x0000000000000088ULL /* PTE not found (Single Level Radix) 0b10001000 */ > +#define CXL_PSL9_DSISR_An_PF_RGC 0x000000000000008CULL /* PTE not found (Radix Guest (child)) 0b10001100 */ > +#define CXL_PSL9_DSISR_An_PF_RGP 0x0000000000000090ULL /* PTE not found (Radix Guest (parent)) 0b10010000 */ > +#define CXL_PSL9_DSISR_An_PF_HRH 0x0000000000000094ULL /* PTE not found (HPT/Radix Host) 0b10010100 */ > +#define CXL_PSL9_DSISR_An_PF_STEG 0x000000000000009CULL /* PTE not found (STEG VA) 0b10011100 */ > + > /****** CXL_PSL_TFC_An ******************************************************/ > #define CXL_PSL_TFC_An_A (1ull << (63-28)) /* Acknowledge non-translation fault */ > #define CXL_PSL_TFC_An_C (1ull << (63-29)) /* Continue (abort transaction) */ > #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */ > #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL transaction */ > > +/****** CXL_XSL9_IERAT_ERAT - CAIA 2 **********************************/ > +#define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */ > +#define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */ > +#define CXL_XSL9_IERAT_PRS (1ull << (63-4)) /* PRS bit for Radix invalidations */ > +#define CXL_XSL9_IERAT_INVR (1ull << (63-3)) /* Invalidate Radix */ > +#define CXL_XSL9_IERAT_IALL (1ull << (63-8)) /* Invalidate All */ > +#define CXL_XSL9_IERAT_IINPROG (1ull << (63-63)) /* Invalidate in progress */ > + > /* cxl_process_element->software_status */ > #define CXL_PE_SOFTWARE_STATE_V (1ul << (31 - 0)) /* Valid */ > #define CXL_PE_SOFTWARE_STATE_C (1ul << (31 - 29)) /* Complete */ > @@ -654,25 +703,38 @@ int cxl_pci_reset(struct cxl *adapter); > void cxl_pci_release_afu(struct device *dev); > ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len); > > -/* common == phyp + powernv */ > +/* common == phyp + powernv - CAIA 1&2 */ > struct cxl_process_element_common { > __be32 tid; > __be32 pid; > __be64 csrp; > - __be64 aurp0; > - __be64 aurp1; > - __be64 sstp0; > - __be64 sstp1; > + union { > + struct { > + __be64 aurp0; > + __be64 aurp1; > + __be64 sstp0; > + __be64 sstp1; > + } psl8; /* CAIA 1 */ > + struct { > + u8 reserved2[8]; > + u8 reserved3[8]; > + u8 reserved4[8]; > + u8 reserved5[8]; > + } psl9; /* CAIA 2 */ > + } u; > __be64 amr; > - u8 reserved3[4]; > + u8 reserved6[4]; > __be64 wed; > } __packed; > > -/* just powernv */ > +/* just powernv - CAIA 1&2 */ > struct cxl_process_element { > __be64 sr; > __be64 SPOffset; > - __be64 sdr; > + union { > + __be64 sdr; /* CAIA 1 */ > + u8 reserved1[8]; /* CAIA 2 */ > + } u; > __be64 haurp; > __be32 ctxtime; > __be16 ivte_offsets[4]; > @@ -761,6 +823,16 @@ static inline bool cxl_is_power8(void) > return false; > } > > +static inline bool cxl_is_power9(void) > +{ > + /* intermediate solution */ > + if (!cxl_is_power8() && > + (cpu_has_feature(CPU_FTRS_POWER9) || > + cpu_has_feature(CPU_FTR_POWER9_DD1))) > + return true; > + return false; > +} > + > static inline bool cxl_is_psl8(struct cxl_afu *afu) > { > if (afu->adapter->caia_major == 1) > @@ -768,6 +840,13 @@ static inline bool cxl_is_psl8(struct cxl_afu *afu) > return false; > } > > +static inline bool cxl_is_psl9(struct cxl_afu *afu) > +{ > + if (afu->adapter->caia_major == 2) > + return true; > + return false; > +} > + > ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, > loff_t off, size_t count); > > @@ -794,7 +873,6 @@ int cxl_update_properties(struct device_node *dn, struct property *new_prop); > > void cxl_remove_adapter_nr(struct cxl *adapter); > > -int cxl_alloc_spa(struct cxl_afu *afu); > void cxl_release_spa(struct cxl_afu *afu); > > dev_t cxl_get_dev(void); > @@ -832,9 +910,13 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count); > void afu_release_irqs(struct cxl_context *ctx, void *cookie); > void afu_irq_name_free(struct cxl_context *ctx); > > +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, u64 amr); > int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr); > +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu); > int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu); > +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 wed, u64 amr); > int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 wed, u64 amr); > +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx); > void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx); > > #ifdef CONFIG_DEBUG_FS > @@ -845,9 +927,12 @@ int cxl_debugfs_adapter_add(struct cxl *adapter); > void cxl_debugfs_adapter_remove(struct cxl *adapter); > int cxl_debugfs_afu_add(struct cxl_afu *afu); > void cxl_debugfs_afu_remove(struct cxl_afu *afu); > +void cxl_stop_trace_psl9(struct cxl *cxl); > void cxl_stop_trace_psl8(struct cxl *cxl); > +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir); > void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir); > void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, struct dentry *dir); > +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir); > void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir); > > #else /* CONFIG_DEBUG_FS */ > @@ -879,10 +964,19 @@ static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu) > { > } > > +static inline void cxl_stop_trace_psl9(struct cxl *cxl) > +{ > +} > + > static inline void cxl_stop_trace_psl8(struct cxl *cxl) > { > } > > +static inline void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, > + struct dentry *dir) > +{ > +} > + > static inline void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, > struct dentry *dir) > { > @@ -893,6 +987,10 @@ static inline void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, > { > } > > +static inline void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir) > +{ > +} > + > static inline void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) > { > } > @@ -951,7 +1049,9 @@ struct cxl_irq_info { > }; > > void cxl_assign_psn_space(struct cxl_context *ctx); > +int cxl_invalidate_all_psl9(struct cxl *adapter); > int cxl_invalidate_all_psl8(struct cxl *adapter); > +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info); > irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info); > irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct cxl_irq_info *irq_info); > int cxl_register_one_irq(struct cxl *adapter, irq_handler_t handler, > @@ -964,6 +1064,7 @@ int cxl_data_cache_flush(struct cxl *adapter); > int cxl_afu_disable(struct cxl_afu *afu); > int cxl_psl_purge(struct cxl_afu *afu); > > +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx); > void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx); > void cxl_native_err_irq_dump_regs(struct cxl *adapter); > int cxl_pci_vphb_add(struct cxl_afu *afu); > diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c > index 43a1a27..eae9d74 100644 > --- a/drivers/misc/cxl/debugfs.c > +++ b/drivers/misc/cxl/debugfs.c > @@ -15,6 +15,12 @@ > > static struct dentry *cxl_debugfs; > > +void cxl_stop_trace_psl9(struct cxl *adapter) > +{ > + /* Stop the trace */ > + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x4480000000000000ULL); > +} > + > void cxl_stop_trace_psl8(struct cxl *adapter) > { > int slice; > @@ -53,6 +59,14 @@ static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, > (void __force *)value, &fops_io_x64); > } > > +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir) > +{ > + debugfs_create_io_x64("fir1", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR1)); > + debugfs_create_io_x64("fir2", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR2)); > + debugfs_create_io_x64("fir_cntl", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR_CNTL)); > + debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_TRACECFG)); > +} > + > void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) > { > debugfs_create_io_x64("fir1", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_FIR1)); > @@ -92,6 +106,11 @@ void cxl_debugfs_adapter_remove(struct cxl *adapter) > debugfs_remove_recursive(adapter->debugfs); > } > > +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir) > +{ > + debugfs_create_io_x64("serr", S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SERR_An)); > +} > + > void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) > { > debugfs_create_io_x64("sstp0", S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_SSTP0_An)); > diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c > index f24c15c..381ae70 100644 > --- a/drivers/misc/cxl/fault.c > +++ b/drivers/misc/cxl/fault.c > @@ -146,25 +146,26 @@ static void cxl_handle_page_fault(struct cxl_context *ctx, > return cxl_ack_ae(ctx); > } > > - /* > - * update_mmu_cache() will not have loaded the hash since current->trap > - * is not a 0x400 or 0x300, so just call hash_page_mm() here. > - */ > - access = _PAGE_PRESENT | _PAGE_READ; > - if (dsisr & CXL_PSL_DSISR_An_S) > - access |= _PAGE_WRITE; > - > - access |= _PAGE_PRIVILEGED; > - if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) > - access &= ~_PAGE_PRIVILEGED; > - > - if (dsisr & DSISR_NOHPTE) > - inv_flags |= HPTE_NOHPTE_UPDATE; > - > - local_irq_save(flags); > - hash_page_mm(mm, dar, access, 0x300, inv_flags); > - local_irq_restore(flags); > - > + if (!radix_enabled()) { > + /* > + * update_mmu_cache() will not have loaded the hash since current->trap > + * is not a 0x400 or 0x300, so just call hash_page_mm() here. > + */ > + access = _PAGE_PRESENT | _PAGE_READ; > + if (dsisr & CXL_PSL_DSISR_An_S) > + access |= _PAGE_WRITE; > + > + access |= _PAGE_PRIVILEGED; > + if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) > + access &= ~_PAGE_PRIVILEGED; > + > + if (dsisr & DSISR_NOHPTE) > + inv_flags |= HPTE_NOHPTE_UPDATE; > + > + local_irq_save(flags); > + hash_page_mm(mm, dar, access, 0x300, inv_flags); > + local_irq_restore(flags); > + } > pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe); > cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0); > } > @@ -179,12 +180,33 @@ static struct mm_struct *get_mem_context(struct cxl_context *ctx) > return NULL; > > if (!atomic_inc_not_zero(&ctx->mm->mm_users)) > - return ctx->mm; > + return NULL; > > - return NULL; > + return ctx->mm; > } This looks wrong... I think the previous version was correct. Either way, only one code change should be enough. > > +static bool cxl_is_segment_miss(struct cxl_context *ctx, u64 dsisr) > +{ > + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DS)) > + return true; > > + return false; > +} > + > +static bool cxl_is_page_fault(struct cxl_context *ctx, u64 dsisr) > +{ > + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DM)) > + return true; > + > + if ((cxl_is_psl9(ctx->afu)) && > + ((dsisr & CXL_PSL9_DSISR_An_CO_MASK) & > + (CXL_PSL9_DSISR_An_PF_SLR | CXL_PSL9_DSISR_An_PF_RGC | > + CXL_PSL9_DSISR_An_PF_RGP | CXL_PSL9_DSISR_An_PF_HRH | > + CXL_PSL9_DSISR_An_PF_STEG))) > + return true; > + > + return false; > +} > > void cxl_handle_fault(struct work_struct *fault_work) > { > @@ -230,14 +252,12 @@ void cxl_handle_fault(struct work_struct *fault_work) > } > } > > - if (cxl_is_psl8(ctx->afu)) { > - if (dsisr & CXL_PSL_DSISR_An_DS) > - cxl_handle_segment_miss(ctx, mm, dar); > - else if (dsisr & CXL_PSL_DSISR_An_DM) > - cxl_handle_page_fault(ctx, mm, dsisr, dar); > - else > - WARN(1, "cxl_handle_fault has nothing to handle\n"); > - } > + if (cxl_is_segment_miss(ctx, dsisr)) > + cxl_handle_segment_miss(ctx, mm, dar); > + else if (cxl_is_page_fault(ctx, dsisr)) > + cxl_handle_page_fault(ctx, mm, dsisr, dar); > + else > + WARN(1, "cxl_handle_fault has nothing to handle\n"); > > if (mm) > mmput(mm); > diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c > index 3ad7381..f58b4b6c 100644 > --- a/drivers/misc/cxl/guest.c > +++ b/drivers/misc/cxl/guest.c > @@ -551,13 +551,13 @@ static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr) > elem->common.tid = cpu_to_be32(0); /* Unused */ > elem->common.pid = cpu_to_be32(pid); > elem->common.csrp = cpu_to_be64(0); /* disable */ > - elem->common.aurp0 = cpu_to_be64(0); /* disable */ > - elem->common.aurp1 = cpu_to_be64(0); /* disable */ > + elem->common.u.psl8.aurp0 = cpu_to_be64(0); /* disable */ > + elem->common.u.psl8.aurp1 = cpu_to_be64(0); /* disable */ > > cxl_prefault(ctx, wed); > > - elem->common.sstp0 = cpu_to_be64(ctx->sstp0); > - elem->common.sstp1 = cpu_to_be64(ctx->sstp1); > + elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); > + elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); > > /* > * Ensure we have at least one interrupt allocated to take faults for > diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c > index fa9f8a2..1eb5168 100644 > --- a/drivers/misc/cxl/irq.c > +++ b/drivers/misc/cxl/irq.c > @@ -34,6 +34,59 @@ static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 da > return IRQ_HANDLED; > } > > +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info) > +{ > + u64 dsisr, dar; > + > + dsisr = irq_info->dsisr; > + dar = irq_info->dar; > + > + trace_cxl_psl9_irq(ctx, irq, dsisr, dar); > + > + pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar); > + > + if (dsisr & CXL_PSL9_DSISR_An_TF) { > + pr_devel("CXL interrupt: Scheduling translation fault" > + " handling for later (pe: %i)\n", ctx->pe); > + return schedule_cxl_fault(ctx, dsisr, dar); > + } > + > + if (dsisr & CXL_PSL9_DSISR_An_PE) > + return cxl_ops->handle_psl_slice_error(ctx, dsisr, > + irq_info->errstat); > + if (dsisr & CXL_PSL9_DSISR_An_AE) { > + pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err); > + > + if (ctx->pending_afu_err) { > + /* > + * This shouldn't happen - the PSL treats these errors > + * as fatal and will have reset the AFU, so there's not > + * much point buffering multiple AFU errors. > + * OTOH if we DO ever see a storm of these come in it's > + * probably best that we log them somewhere: > + */ > + dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " > + "undelivered to pe %i: 0x%016llx\n", > + ctx->pe, irq_info->afu_err); > + } else { > + spin_lock(&ctx->lock); > + ctx->afu_err = irq_info->afu_err; > + ctx->pending_afu_err = 1; > + spin_unlock(&ctx->lock); > + > + wake_up_all(&ctx->wq); > + } > + > + cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_A, 0); > + return IRQ_HANDLED; > + } > + if (dsisr & CXL_PSL9_DSISR_An_OC) > + pr_devel("CXL interrupt: OS Context Warning\n"); > + > + WARN(1, "Unhandled CXL PSL IRQ\n"); > + return IRQ_HANDLED; > +} > + > irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info) > { > u64 dsisr, dar; > diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c > index 7b86ffa..67c9bc6 100644 > --- a/drivers/misc/cxl/native.c > +++ b/drivers/misc/cxl/native.c > @@ -120,6 +120,7 @@ int cxl_psl_purge(struct cxl_afu *afu) > u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); > u64 dsisr, dar; > u64 start, end; > + u64 trans_fault = 0x0ULL; > unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); > int rc = 0; > > @@ -127,6 +128,11 @@ int cxl_psl_purge(struct cxl_afu *afu) > > pr_devel("PSL purge request\n"); > > + if (cxl_is_psl8(afu)) > + trans_fault = CXL_PSL_DSISR_TRANS; > + if (cxl_is_psl9(afu)) > + trans_fault = CXL_PSL9_DSISR_An_TF; > + > if (!cxl_ops->link_ok(afu->adapter, afu)) { > dev_warn(&afu->dev, "PSL Purge called with link down, ignoring\n"); > rc = -EIO; > @@ -158,22 +164,21 @@ int cxl_psl_purge(struct cxl_afu *afu) > pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx" > " PSL_DSISR: 0x%016llx\n", > PSL_CNTL, dsisr); > - if (cxl_is_psl8(afu)) { > - if (dsisr & CXL_PSL_DSISR_TRANS) { > - dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); > - dev_notice(&afu->dev, "PSL purge terminating " > - "pending translation, " > - "DSISR: 0x%016llx, DAR: 0x%016llx\n", > - dsisr, dar); > - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); > - } else if (dsisr) { > - dev_notice(&afu->dev, "PSL purge acknowledging " > - "pending non-translation fault, " > - "DSISR: 0x%016llx\n", dsisr); > - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); > - } else { > - cpu_relax(); > - } > + > + if (dsisr & trans_fault) { > + dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); > + dev_notice(&afu->dev, "PSL purge terminating " > + "pending translation, " > + "DSISR: 0x%016llx, DAR: 0x%016llx\n", > + dsisr, dar); > + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); > + } else if (dsisr) { > + dev_notice(&afu->dev, "PSL purge acknowledging " > + "pending non-translation fault, " > + "DSISR: 0x%016llx\n", dsisr); > + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); > + } else { > + cpu_relax(); > } > PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An); > } > @@ -205,7 +210,7 @@ static int spa_max_procs(int spa_size) > return ((spa_size / 8) - 96) / 17; > } > > -int cxl_alloc_spa(struct cxl_afu *afu) > +static int cxl_alloc_spa(struct cxl_afu *afu, int mode) > { > unsigned spa_size; > > @@ -218,7 +223,8 @@ int cxl_alloc_spa(struct cxl_afu *afu) > if (spa_size > 0x100000) { > dev_warn(&afu->dev, "num_of_processes too large for the SPA, limiting to %i (0x%x)\n", > afu->native->spa_max_procs, afu->native->spa_size); > - afu->num_procs = afu->native->spa_max_procs; > + if (mode != CXL_MODE_DEDICATED) > + afu->num_procs = afu->native->spa_max_procs; > break; > } > > @@ -267,6 +273,35 @@ void cxl_release_spa(struct cxl_afu *afu) > } > } > > +/* Invalidation of all ERAT entries is no longer required by CAIA2. Use > + * only for debug > + */ > +int cxl_invalidate_all_psl9(struct cxl *adapter) > +{ > + unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); > + u64 ierat; > + > + pr_devel("CXL adapter - invalidation of all ERAT entries\n"); > + > + /* Invalidates all ERAT entries for Radix or HPT */ > + ierat = CXL_XSL9_IERAT_IALL; > + if (radix_enabled()) > + ierat |= CXL_XSL9_IERAT_INVR; > + cxl_p1_write(adapter, CXL_XSL9_IERAT, ierat); > + > + while (cxl_p1_read(adapter, CXL_XSL9_IERAT) & CXL_XSL9_IERAT_IINPROG) { > + if (time_after_eq(jiffies, timeout)) { > + dev_warn(&adapter->dev, > + "WARNING: CXL adapter invalidation of all ERAT entries timed out!\n"); > + return -EBUSY; > + } > + if (!cxl_ops->link_ok(adapter, NULL)) > + return -EIO; > + cpu_relax(); > + } > + return 0; > +} > + > int cxl_invalidate_all_psl8(struct cxl *adapter) > { > unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); > @@ -503,7 +538,7 @@ static int activate_afu_directed(struct cxl_afu *afu) > > afu->num_procs = afu->max_procs_virtualised; > if (afu->native->spa == NULL) { > - if (cxl_alloc_spa(afu)) > + if (cxl_alloc_spa(afu, CXL_MODE_DIRECTED)) > return -ENOMEM; > } > attach_spa(afu); > @@ -553,10 +588,19 @@ static u64 calculate_sr(struct cxl_context *ctx) > sr |= (mfmsr() & MSR_SF) | CXL_PSL_SR_An_HV; > } else { > sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R; > - sr &= ~(CXL_PSL_SR_An_HV); > + if (radix_enabled()) > + sr |= CXL_PSL_SR_An_HV; > + else > + sr &= ~(CXL_PSL_SR_An_HV); > if (!test_tsk_thread_flag(current, TIF_32BIT)) > sr |= CXL_PSL_SR_An_SF; > } > + if (cxl_is_psl9(ctx->afu)) { > + if (radix_enabled()) > + sr |= CXL_PSL_SR_An_XLAT_ror; > + else > + sr |= CXL_PSL_SR_An_XLAT_hpt; > + } > return sr; > } > > @@ -589,6 +633,70 @@ static void update_ivtes_directed(struct cxl_context *ctx) > WARN_ON(add_process_element(ctx)); > } > > +static int process_element_entry(struct cxl_context *ctx, u64 wed, u64 amr) Could we have a "9" in the name, to show that's it's only used for psl9? I was actually wondering if we could refactor to also use it on psl8, but it seems that's there's enough low-level details being different that it's ok to keep the 2 version separate. > +{ > + u32 pid; > + > + cxl_assign_psn_space(ctx); > + > + ctx->elem->ctxtime = 0; /* disable */ > + ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); > + ctx->elem->haurp = 0; /* disable */ > + > + if (ctx->kernel) > + pid = 0; > + else { > + if (ctx->mm == NULL) { > + pr_devel("%s: unable to get mm for pe=%d pid=%i\n", > + __func__, ctx->pe, pid_nr(ctx->pid)); > + return -EINVAL; > + } > + pid = ctx->mm->context.id; > + } > + > + ctx->elem->common.tid = 0; > + ctx->elem->common.pid = cpu_to_be32(pid); > + > + ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); > + > + ctx->elem->common.csrp = 0; /* disable */ > + > + cxl_prefault(ctx, wed); > + > + /* > + * Ensure we have the multiplexed PSL interrupt set up to take faults > + * for kernel contexts that may not have allocated any AFU IRQs at all: > + */ > + if (ctx->irqs.range[0] == 0) { > + ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq; > + ctx->irqs.range[0] = 1; > + } > + > + ctx->elem->common.amr = cpu_to_be64(amr); > + ctx->elem->common.wed = cpu_to_be64(wed); > + > + return 0; > +} > + > +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, u64 amr) > +{ > + int result; > + > + /* fill the process element entry */ > + result = process_element_entry(ctx, wed, amr); > + if (result) > + return result; > + > + update_ivtes_directed(ctx); > + > + /* first guy needs to enable */ > + result = cxl_ops->afu_check_and_enable(ctx->afu); > + if (result) > + return result; > + > + return add_process_element(ctx); > +} > + > int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) > { > u32 pid; > @@ -599,7 +707,7 @@ int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) > ctx->elem->ctxtime = 0; /* disable */ > ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); > ctx->elem->haurp = 0; /* disable */ > - ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1)); > + ctx->elem->u.sdr = cpu_to_be64(mfspr(SPRN_SDR1)); > > pid = current->pid; > if (ctx->kernel) > @@ -610,13 +718,13 @@ int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) > ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); > > ctx->elem->common.csrp = 0; /* disable */ > - ctx->elem->common.aurp0 = 0; /* disable */ > - ctx->elem->common.aurp1 = 0; /* disable */ > + ctx->elem->common.u.psl8.aurp0 = 0; /* disable */ > + ctx->elem->common.u.psl8.aurp1 = 0; /* disable */ > > cxl_prefault(ctx, wed); > > - ctx->elem->common.sstp0 = cpu_to_be64(ctx->sstp0); > - ctx->elem->common.sstp1 = cpu_to_be64(ctx->sstp1); > + ctx->elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); > + ctx->elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); > > /* > * Ensure we have the multiplexed PSL interrupt set up to take faults > @@ -682,6 +790,31 @@ static int deactivate_afu_directed(struct cxl_afu *afu) > return 0; > } > > +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu) > +{ > + dev_info(&afu->dev, "Activating dedicated process mode\n"); > + > + /* If XSL is set to dedicated mode (Set in PSL_SCNTL reg), the > + * XSL and AFU are programmed to work with a single context. > + * The context information should be configured in the SPA area > + * index 0 (so PSL_SPAP must be configured before enabling the > + * AFU). > + */ > + afu->num_procs = 1; > + if (afu->native->spa == NULL) { > + if (cxl_alloc_spa(afu, CXL_MODE_DEDICATED)) > + return -ENOMEM; > + } > + attach_spa(afu); > + > + cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process); > + cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | CXL_PSL_ID_An_L); > + > + afu->current_mode = CXL_MODE_DEDICATED; > + > + return cxl_chardev_d_afu_add(afu); > +} > + > int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu) > { > dev_info(&afu->dev, "Activating dedicated process mode\n"); > @@ -705,6 +838,16 @@ int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu) > return cxl_chardev_d_afu_add(afu); > } > > +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx) > +{ > + int r; > + > + for (r = 0; r < CXL_IRQ_RANGES; r++) { > + ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]); > + ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]); > + } > +} > + > void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx) > { > struct cxl_afu *afu = ctx->afu; > @@ -721,6 +864,26 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx) > ((u64)ctx->irqs.range[3] & 0xffff)); > } > > +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 wed, u64 amr) > +{ > + struct cxl_afu *afu = ctx->afu; > + int result; > + > + /* fill the process element entry */ > + result = process_element_entry(ctx, wed, amr); > + if (result) > + return result; > + > + if (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes) > + afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx); > + > + result = cxl_ops->afu_reset(afu); > + if (result) > + return result; > + > + return afu_enable(afu); > +} > + > int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 wed, u64 amr) > { > struct cxl_afu *afu = ctx->afu; > @@ -892,6 +1055,21 @@ static int native_get_irq_info(struct cxl_afu *afu, struct cxl_irq_info *info) > return 0; > } > > +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx) > +{ > + u64 fir1, fir2, serr; > + > + fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR1); > + fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR2); > + > + dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); > + dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); > + if (ctx->afu->adapter->native->sl_ops->register_serr_irq) { > + serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); > + cxl_afu_decode_psl_serr(ctx->afu, serr); > + } > +} > + > void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx) > { > u64 fir1, fir2, fir_slice, serr, afu_debug; > @@ -928,9 +1106,20 @@ static irqreturn_t native_handle_psl_slice_error(struct cxl_context *ctx, > return cxl_ops->ack_irq(ctx, 0, errstat); > } > > +static bool cxl_is_translation_fault(struct cxl_afu *afu, u64 dsisr) > +{ > + if ((cxl_is_psl8(afu)) && (dsisr & CXL_PSL_DSISR_TRANS)) > + return true; > + > + if ((cxl_is_psl9(afu)) && (dsisr & CXL_PSL9_DSISR_An_TF)) > + return true; > + > + return false; > +} > + > irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct cxl_irq_info *irq_info) > { > - if (irq_info->dsisr & CXL_PSL_DSISR_TRANS) > + if (cxl_is_translation_fault(afu, irq_info->dsisr)) > cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); > else > cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); > @@ -1001,6 +1190,9 @@ static void native_irq_wait(struct cxl_context *ctx) > if (cxl_is_psl8(ctx->afu) && > ((dsisr & CXL_PSL_DSISR_PENDING) == 0)) > return; > + if (cxl_is_psl9(ctx->afu) && > + ((dsisr & CXL_PSL9_DSISR_PENDING) == 0)) > + return; > /* > * We are waiting for the workqueue to process our > * irq, so need to let that run here. > @@ -1127,8 +1319,7 @@ int cxl_native_register_serr_irq(struct cxl_afu *afu) > } > > serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); > - if (cxl_is_power8()) > - serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); > + serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); This looks wrong. Previous version was setting the SERR differently on p9, since some errors are masked by default. So it looks like the above is not correct? Fred > cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); > > return 0; > diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c > index 360c231..428c80b 100644 > --- a/drivers/misc/cxl/pci.c > +++ b/drivers/misc/cxl/pci.c > @@ -60,7 +60,7 @@ > #define CXL_VSEC_PROTOCOL_MASK 0xe0 > #define CXL_VSEC_PROTOCOL_1024TB 0x80 > #define CXL_VSEC_PROTOCOL_512TB 0x40 > -#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8 uses this */ > +#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8/9 uses this */ > #define CXL_VSEC_PROTOCOL_ENABLE 0x01 > > #define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \ > @@ -326,14 +326,20 @@ static void dump_afu_descriptor(struct cxl_afu *afu) > > #define P8_CAPP_UNIT0_ID 0xBA > #define P8_CAPP_UNIT1_ID 0XBE > +#define P9_CAPP_UNIT0_ID 0xC0 > +#define P9_CAPP_UNIT1_ID 0xE0 > > -static u64 get_capp_unit_id(struct device_node *np) > +static u32 get_phb_index(struct device_node *np) > { > u32 phb_index; > > if (of_property_read_u32(np, "ibm,phb-index", &phb_index)) > - return 0; > + return -ENODEV; > + return phb_index; > +} > > +static u64 get_capp_unit_id(struct device_node *np, u32 phb_index) > +{ > /* > * POWER 8: > * - For chips other than POWER8NVL, we only have CAPP 0, > @@ -352,10 +358,25 @@ static u64 get_capp_unit_id(struct device_node *np) > return P8_CAPP_UNIT1_ID; > } > > + /* > + * POWER 9: > + * PEC0 (PHB0). Capp ID = CAPP0 (0b1100_0000) > + * PEC1 (PHB1 - PHB2). No capi mode > + * PEC2 (PHB3 - PHB4 - PHB5): Capi mode on PHB3 only. Capp ID = CAPP1 (0b1110_0000) > + */ > + if (cxl_is_power9()) { > + if (phb_index == 0) > + return P9_CAPP_UNIT0_ID; > + > + if (phb_index == 3) > + return P9_CAPP_UNIT1_ID; > + } > + > return 0; > } > > -static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id) > +static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, > + u32 *phb_index, u64 *capp_unit_id) > { > struct device_node *np; > const __be32 *prop; > @@ -367,8 +388,16 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id > np = of_get_next_parent(np); > if (!np) > return -ENODEV; > + > *chipid = be32_to_cpup(prop); > - *capp_unit_id = get_capp_unit_id(np); > + > + *phb_index = get_phb_index(np); > + if (*phb_index == -ENODEV) { > + pr_err("cxl: invalid phb index\n"); > + return -ENODEV; > + } > + > + *capp_unit_id = get_capp_unit_id(np, *phb_index); > of_node_put(np); > if (!*capp_unit_id) { > pr_err("cxl: invalid capp unit id\n"); > @@ -378,14 +407,97 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id > return 0; > } > > +static int init_implementation_adapter_regs_psl9(struct cxl *adapter, struct pci_dev *dev) > +{ > + u64 xsl_dsnctl, psl_fircntl; > + u64 chipid; > + u32 phb_index; > + u64 capp_unit_id; > + int rc; > + > + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); > + if (rc) > + return rc; > + > + /* CAPI Identifier bits [0:7] > + * bit 61:60 MSI bits --> 0 > + * bit 59 TVT selector --> 0 > + */ > + /* Tell XSL where to route data to. > + * The field chipid should match the PHB CAPI_CMPM register > + */ > + xsl_dsnctl = ((u64)0x2 << (63-7)); /* Bit 57 */ > + xsl_dsnctl |= (capp_unit_id << (63-15)); > + > + /* nMMU_ID Defaults to: b’000001001’*/ > + xsl_dsnctl |= ((u64)0x09 << (63-28)); > + > + if (cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)) { > + /* Used to identify CAPI packets which should be sorted into > + * the Non-Blocking queues by the PHB. This field should match > + * the PHB PBL_NBW_CMPM register > + * nbwind=0x03, bits [57:58], must include capi indicator. > + * Not supported on P9 DD1. > + */ > + xsl_dsnctl |= ((u64)0x03 << (63-47)); > + > + /* Upper 16b address bits of ASB_Notify messages sent to the > + * system. Need to match the PHB’s ASN Compare/Mask Register. > + * Not supported on P9 DD1. > + */ > + xsl_dsnctl |= ((u64)0x04 << (63-55)); > + } > + > + cxl_p1_write(adapter, CXL_XSL9_DSNCTL, xsl_dsnctl); > + > + /* Set fir_cntl to recommended value for production env */ > + psl_fircntl = (0x2ULL << (63-3)); /* ce_report */ > + psl_fircntl |= (0x1ULL << (63-6)); /* FIR_report */ > + psl_fircntl |= 0x1ULL; /* ce_thresh */ > + cxl_p1_write(adapter, CXL_PSL9_FIR_CNTL, psl_fircntl); > + > + /* vccredits=0x1 pcklat=0x4 */ > + cxl_p1_write(adapter, CXL_PSL9_DSNDCTL, 0x0000000000001810ULL); > + > + /* For debugging with trace arrays. > + * Configure RX trace 0 segmented mode. > + * Configure CT trace 0 segmented mode. > + * Configure LA0 trace 0 segmented mode. > + * Configure LA1 trace 0 segmented mode. > + */ > + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000000ULL); > + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000003ULL); > + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000005ULL); > + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000006ULL); > + > + /* A response to an ASB_Notify request is returned by the > + * system as an MMIO write to the address defined in > + * the PSL_TNR_ADDR register > + */ > + /* PSL_TNR_ADDR */ > + > + /* NORST */ > + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL); > + > + /* allocate the apc machines */ > + cxl_p1_write(adapter, CXL_PSL9_APCDEDTYPE, 0x40000003FFFF0000ULL); > + > + /* Disable vc dd1 fix */ > + if ((cxl_is_power9() && cpu_has_feature(CPU_FTR_POWER9_DD1))) > + cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0400000000000001ULL); > + > + return 0; > +} > + > static int init_implementation_adapter_regs_psl8(struct cxl *adapter, struct pci_dev *dev) > { > u64 psl_dsnctl, psl_fircntl; > u64 chipid; > + u32 phb_index; > u64 capp_unit_id; > int rc; > > - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); > + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); > if (rc) > return rc; > > @@ -414,10 +526,11 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ > { > u64 xsl_dsnctl; > u64 chipid; > + u32 phb_index; > u64 capp_unit_id; > int rc; > > - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); > + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); > if (rc) > return rc; > > @@ -435,6 +548,12 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ > /* For the PSL this is a multiple for 0 < n <= 7: */ > #define PSL_2048_250MHZ_CYCLES 1 > > +static void write_timebase_ctrl_psl9(struct cxl *adapter) > +{ > + cxl_p1_write(adapter, CXL_PSL9_TB_CTLSTAT, > + TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES)); > +} > + > static void write_timebase_ctrl_psl8(struct cxl *adapter) > { > cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT, > @@ -456,6 +575,11 @@ static void write_timebase_ctrl_xsl(struct cxl *adapter) > TBSYNC_CNT(XSL_4000_CLOCKS)); > } > > +static u64 timebase_read_psl9(struct cxl *adapter) > +{ > + return cxl_p1_read(adapter, CXL_PSL9_Timebase); > +} > + > static u64 timebase_read_psl8(struct cxl *adapter) > { > return cxl_p1_read(adapter, CXL_PSL_Timebase); > @@ -514,6 +638,11 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) > return; > } > > +static int init_implementation_afu_regs_psl9(struct cxl_afu *afu) > +{ > + return 0; > +} > + > static int init_implementation_afu_regs_psl8(struct cxl_afu *afu) > { > /* read/write masks for this slice */ > @@ -612,7 +741,7 @@ static int setup_cxl_bars(struct pci_dev *dev) > /* > * BAR 4/5 has a special meaning for CXL and must be programmed with a > * special value corresponding to the CXL protocol address range. > - * For POWER 8 that means bits 48:49 must be set to 10 > + * For POWER 8/9 that means bits 48:49 must be set to 10 > */ > pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000); > pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000); > @@ -997,6 +1126,52 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu) > return 0; > } > > +static int sanitise_afu_regs_psl9(struct cxl_afu *afu) > +{ > + u64 reg; > + > + /* > + * Clear out any regs that contain either an IVTE or address or may be > + * waiting on an acknowledgment to try to be a bit safer as we bring > + * it online > + */ > + reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); > + if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { > + dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg); > + if (cxl_ops->afu_reset(afu)) > + return -EIO; > + if (cxl_afu_disable(afu)) > + return -EIO; > + if (cxl_psl_purge(afu)) > + return -EIO; > + } > + cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000); > + cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000); > + reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An); > + if (reg) { > + dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg); > + if (reg & CXL_PSL9_DSISR_An_TF) > + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); > + else > + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); > + } > + if (afu->adapter->native->sl_ops->register_serr_irq) { > + reg = cxl_p1n_read(afu, CXL_PSL_SERR_An); > + if (reg) { > + if (reg & ~0x000000007fffffff) > + dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg); > + cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff); > + } > + } > + reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); > + if (reg) { > + dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg); > + cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg); > + } > + > + return 0; > +} > + > static int sanitise_afu_regs_psl8(struct cxl_afu *afu) > { > u64 reg; > @@ -1254,10 +1429,10 @@ int cxl_pci_reset(struct cxl *adapter) > > /* > * The adapter is about to be reset, so ignore errors. > - * Not supported on P9 DD1 but don't forget to enable it > - * on P9 DD2 > + * Not supported on P9 DD1 > */ > - if (cxl_is_power8()) > + if ((cxl_is_power8()) || > + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) > cxl_data_cache_flush(adapter); > > /* pcie_warm_reset requests a fundamental pci reset which includes a > @@ -1393,6 +1568,9 @@ static bool cxl_compatible_caia_version(struct cxl *adapter) > if (cxl_is_power8() && (adapter->caia_major == 1)) > return true; > > + if (cxl_is_power9() && (adapter->caia_major == 2)) > + return true; > + > return false; > } > > @@ -1460,8 +1638,12 @@ static int sanitise_adapter_regs(struct cxl *adapter) > /* Clear PSL tberror bit by writing 1 to it */ > cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror); > > - if (adapter->native->sl_ops->invalidate_all) > + if (adapter->native->sl_ops->invalidate_all) { > + /* do not invalidate ERAT entries when not reloading on PERST */ > + if (cxl_is_power9() && (adapter->perst_loads_image)) > + return 0; > rc = adapter->native->sl_ops->invalidate_all(adapter); > + } > > return rc; > } > @@ -1546,6 +1728,30 @@ static void cxl_deconfigure_adapter(struct cxl *adapter) > pci_disable_device(pdev); > } > > +static const struct cxl_service_layer_ops psl9_ops = { > + .adapter_regs_init = init_implementation_adapter_regs_psl9, > + .invalidate_all = cxl_invalidate_all_psl9, > + .afu_regs_init = init_implementation_afu_regs_psl9, > + .sanitise_afu_regs = sanitise_afu_regs_psl9, > + .register_serr_irq = cxl_native_register_serr_irq, > + .release_serr_irq = cxl_native_release_serr_irq, > + .handle_interrupt = cxl_irq_psl9, > + .fail_irq = cxl_fail_irq_psl, > + .activate_dedicated_process = cxl_activate_dedicated_process_psl9, > + .attach_afu_directed = cxl_attach_afu_directed_psl9, > + .attach_dedicated_process = cxl_attach_dedicated_process_psl9, > + .update_dedicated_ivtes = cxl_update_dedicated_ivtes_psl9, > + .debugfs_add_adapter_regs = cxl_debugfs_add_adapter_regs_psl9, > + .debugfs_add_afu_regs = cxl_debugfs_add_afu_regs_psl9, > + .psl_irq_dump_registers = cxl_native_irq_dump_regs_psl9, > + .err_irq_dump_registers = cxl_native_err_irq_dump_regs, > + .debugfs_stop_trace = cxl_stop_trace_psl9, > + .write_timebase_ctrl = write_timebase_ctrl_psl9, > + .timebase_read = timebase_read_psl9, > + .capi_mode = OPAL_PHB_CAPI_MODE_CAPI, > + .needs_reset_before_disable = true, > +}; > + > static const struct cxl_service_layer_ops psl8_ops = { > .adapter_regs_init = init_implementation_adapter_regs_psl8, > .invalidate_all = cxl_invalidate_all_psl8, > @@ -1589,6 +1795,9 @@ static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev) > if (cxl_is_power8()) { > dev_info(&dev->dev, "Device uses a PSL8\n"); > adapter->native->sl_ops = &psl8_ops; > + } else { > + dev_info(&dev->dev, "Device uses a PSL9\n"); > + adapter->native->sl_ops = &psl9_ops; > } > } > } > @@ -1659,8 +1868,12 @@ static void cxl_pci_remove_adapter(struct cxl *adapter) > cxl_sysfs_adapter_remove(adapter); > cxl_debugfs_adapter_remove(adapter); > > - /* Flush adapter datacache as its about to be removed */ > - cxl_data_cache_flush(adapter); > + /* Flush adapter datacache as its about to be removed. > + * Not supported on P9 DD1 > + */ > + if ((cxl_is_power8()) || > + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) > + cxl_data_cache_flush(adapter); > > cxl_deconfigure_adapter(adapter); > > @@ -1744,6 +1957,11 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) > return -ENODEV; > } > > + if (cxl_is_power9() && !radix_enabled()) { > + dev_info(&dev->dev, "Only Radix mode supported\n"); > + return -ENODEV; > + } > + > if (cxl_verbose) > dump_cxl_config_space(dev); > > diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h > index 751d611..b8e300a 100644 > --- a/drivers/misc/cxl/trace.h > +++ b/drivers/misc/cxl/trace.h > @@ -17,6 +17,15 @@ > > #include "cxl.h" > > +#define dsisr_psl9_flags(flags) \ > + __print_flags(flags, "|", \ > + { CXL_PSL9_DSISR_An_CO_MASK, "FR" }, \ > + { CXL_PSL9_DSISR_An_TF, "TF" }, \ > + { CXL_PSL9_DSISR_An_PE, "PE" }, \ > + { CXL_PSL9_DSISR_An_AE, "AE" }, \ > + { CXL_PSL9_DSISR_An_OC, "OC" }, \ > + { CXL_PSL9_DSISR_An_S, "S" }) > + > #define DSISR_FLAGS \ > { CXL_PSL_DSISR_An_DS, "DS" }, \ > { CXL_PSL_DSISR_An_DM, "DM" }, \ > @@ -154,6 +163,40 @@ TRACE_EVENT(cxl_afu_irq, > ) > ); > > +TRACE_EVENT(cxl_psl9_irq, > + TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), > + > + TP_ARGS(ctx, irq, dsisr, dar), > + > + TP_STRUCT__entry( > + __field(u8, card) > + __field(u8, afu) > + __field(u16, pe) > + __field(int, irq) > + __field(u64, dsisr) > + __field(u64, dar) > + ), > + > + TP_fast_assign( > + __entry->card = ctx->afu->adapter->adapter_num; > + __entry->afu = ctx->afu->slice; > + __entry->pe = ctx->pe; > + __entry->irq = irq; > + __entry->dsisr = dsisr; > + __entry->dar = dar; > + ), > + > + TP_printk("afu%i.%i pe=%i irq=%i dsisr=0x%016llx dsisr=%s dar=0x%016llx", > + __entry->card, > + __entry->afu, > + __entry->pe, > + __entry->irq, > + __entry->dsisr, > + dsisr_psl9_flags(__entry->dsisr), > + __entry->dar > + ) > +); > + > TRACE_EVENT(cxl_psl_irq, > TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), >
Le 03/04/2017 à 15:05, Frederic Barrat a écrit : > > > Le 28/03/2017 à 17:14, Christophe Lombard a écrit : >> The new Coherent Accelerator Interface Architecture, level 2, for the >> IBM POWER9 brings new content and features: >> - POWER9 Service Layer >> - Registers >> - Radix mode >> - Process element entry >> - Dedicated-Shared Process Programming Model >> - Translation Fault Handling >> - CAPP >> - Memory Context ID >> If a valid mm_struct is found the memory context id is used for each >> transaction associated with the process handle. The PSL uses the >> context ID to find the corresponding process element. >> >> Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> >> --- >> drivers/misc/cxl/context.c | 16 ++- >> drivers/misc/cxl/cxl.h | 137 +++++++++++++++++++++---- >> drivers/misc/cxl/debugfs.c | 19 ++++ >> drivers/misc/cxl/fault.c | 78 ++++++++------ >> drivers/misc/cxl/guest.c | 8 +- >> drivers/misc/cxl/irq.c | 53 ++++++++++ >> drivers/misc/cxl/native.c | 247 >> ++++++++++++++++++++++++++++++++++++++++----- >> drivers/misc/cxl/pci.c | 246 >> +++++++++++++++++++++++++++++++++++++++++--- >> drivers/misc/cxl/trace.h | 43 ++++++++ >> 9 files changed, 752 insertions(+), 95 deletions(-) >> >> diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c >> index ac2531e..45363be 100644 >> --- a/drivers/misc/cxl/context.c >> +++ b/drivers/misc/cxl/context.c >> @@ -188,12 +188,24 @@ int cxl_context_iomap(struct cxl_context *ctx, >> struct vm_area_struct *vma) >> if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { >> if (start + len > ctx->afu->adapter->ps_size) >> return -EINVAL; >> + >> + if (cxl_is_psl9(ctx->afu)) { >> + /* make sure there is a valid problem state >> + * area space for this AFU >> + */ >> + if (ctx->master && !ctx->afu->psa) { >> + pr_devel("AFU doesn't support mmio space\n"); >> + return -EINVAL; >> + } >> + >> + /* Can't mmap until the AFU is enabled */ >> + if (!ctx->afu->enabled) >> + return -EBUSY; >> + } >> } else { >> if (start + len > ctx->psn_size) >> return -EINVAL; >> - } >> >> - if (ctx->afu->current_mode != CXL_MODE_DEDICATED) { >> /* make sure there is a valid per process space for this AFU */ >> if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) { >> pr_devel("AFU doesn't support mmio space\n"); >> diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h >> index 2f2d9e4..aac0504 100644 >> --- a/drivers/misc/cxl/cxl.h >> +++ b/drivers/misc/cxl/cxl.h >> @@ -63,7 +63,7 @@ typedef struct { >> /* Memory maps. Ref CXL Appendix A */ >> >> /* PSL Privilege 1 Memory Map */ >> -/* Configuration and Control area */ >> +/* Configuration and Control area - CAIA 1&2 */ >> static const cxl_p1_reg_t CXL_PSL_CtxTime = {0x0000}; >> static const cxl_p1_reg_t CXL_PSL_ErrIVTE = {0x0008}; >> static const cxl_p1_reg_t CXL_PSL_KEY1 = {0x0010}; >> @@ -98,11 +98,29 @@ static const cxl_p1_reg_t CXL_XSL_Timebase = >> {0x0100}; >> static const cxl_p1_reg_t CXL_XSL_TB_CTLSTAT = {0x0108}; >> static const cxl_p1_reg_t CXL_XSL_FEC = {0x0158}; >> static const cxl_p1_reg_t CXL_XSL_DSNCTL = {0x0168}; >> +/* PSL registers - CAIA 2 */ >> +static const cxl_p1_reg_t CXL_PSL9_CONTROL = {0x0020}; >> +static const cxl_p1_reg_t CXL_XSL9_DSNCTL = {0x0168}; >> +static const cxl_p1_reg_t CXL_PSL9_FIR1 = {0x0300}; >> +static const cxl_p1_reg_t CXL_PSL9_FIR2 = {0x0308}; >> +static const cxl_p1_reg_t CXL_PSL9_Timebase = {0x0310}; >> +static const cxl_p1_reg_t CXL_PSL9_DEBUG = {0x0320}; >> +static const cxl_p1_reg_t CXL_PSL9_FIR_CNTL = {0x0348}; >> +static const cxl_p1_reg_t CXL_PSL9_DSNDCTL = {0x0350}; >> +static const cxl_p1_reg_t CXL_PSL9_TB_CTLSTAT = {0x0340}; >> +static const cxl_p1_reg_t CXL_PSL9_TRACECFG = {0x0368}; >> +static const cxl_p1_reg_t CXL_PSL9_APCDEDALLOC = {0x0378}; >> +static const cxl_p1_reg_t CXL_PSL9_APCDEDTYPE = {0x0380}; >> +static const cxl_p1_reg_t CXL_PSL9_TNR_ADDR = {0x0388}; >> +static const cxl_p1_reg_t CXL_PSL9_GP_CT = {0x0398}; >> +static const cxl_p1_reg_t CXL_XSL9_IERAT = {0x0588}; >> +static const cxl_p1_reg_t CXL_XSL9_ILPP = {0x0590}; >> + >> /* 0x7F00:7FFF Reserved PCIe MSI-X Pending Bit Array area */ >> /* 0x8000:FFFF Reserved PCIe MSI-X Table Area */ >> >> /* PSL Slice Privilege 1 Memory Map */ >> -/* Configuration Area */ >> +/* Configuration Area - CAIA 1&2 */ >> static const cxl_p1n_reg_t CXL_PSL_SR_An = {0x00}; >> static const cxl_p1n_reg_t CXL_PSL_LPID_An = {0x08}; >> static const cxl_p1n_reg_t CXL_PSL_AMBAR_An = {0x10}; >> @@ -111,17 +129,18 @@ static const cxl_p1n_reg_t >> CXL_PSL_ID_An = {0x20}; >> static const cxl_p1n_reg_t CXL_PSL_SERR_An = {0x28}; >> /* Memory Management and Lookaside Buffer Management - CAIA 1*/ >> static const cxl_p1n_reg_t CXL_PSL_SDR_An = {0x30}; >> +/* Memory Management and Lookaside Buffer Management - CAIA 1&2 */ >> static const cxl_p1n_reg_t CXL_PSL_AMOR_An = {0x38}; >> -/* Pointer Area */ >> +/* Pointer Area - CAIA 1&2 */ >> static const cxl_p1n_reg_t CXL_HAURP_An = {0x80}; >> static const cxl_p1n_reg_t CXL_PSL_SPAP_An = {0x88}; >> static const cxl_p1n_reg_t CXL_PSL_LLCMD_An = {0x90}; >> -/* Control Area */ >> +/* Control Area - CAIA 1&2 */ >> static const cxl_p1n_reg_t CXL_PSL_SCNTL_An = {0xA0}; >> static const cxl_p1n_reg_t CXL_PSL_CtxTime_An = {0xA8}; >> static const cxl_p1n_reg_t CXL_PSL_IVTE_Offset_An = {0xB0}; >> static const cxl_p1n_reg_t CXL_PSL_IVTE_Limit_An = {0xB8}; >> -/* 0xC0:FF Implementation Dependent Area */ >> +/* 0xC0:FF Implementation Dependent Area - CAIA 1&2 */ >> static const cxl_p1n_reg_t CXL_PSL_FIR_SLICE_An = {0xC0}; >> static const cxl_p1n_reg_t CXL_AFU_DEBUG_An = {0xC8}; >> /* 0xC0:FF Implementation Dependent Area - CAIA 1 */ >> @@ -131,7 +150,7 @@ static const cxl_p1n_reg_t CXL_PSL_RXCTL_A >> = {0xE0}; >> static const cxl_p1n_reg_t CXL_PSL_SLICE_TRACE = {0xE8}; >> >> /* PSL Slice Privilege 2 Memory Map */ >> -/* Configuration and Control Area */ >> +/* Configuration and Control Area - CAIA 1&2 */ >> static const cxl_p2n_reg_t CXL_PSL_PID_TID_An = {0x000}; >> static const cxl_p2n_reg_t CXL_CSRP_An = {0x008}; >> /* Configuration and Control Area - CAIA 1 */ >> @@ -145,17 +164,17 @@ static const cxl_p2n_reg_t CXL_PSL_AMR_An = >> {0x030}; >> static const cxl_p2n_reg_t CXL_SLBIE_An = {0x040}; >> static const cxl_p2n_reg_t CXL_SLBIA_An = {0x048}; >> static const cxl_p2n_reg_t CXL_SLBI_Select_An = {0x050}; >> -/* Interrupt Registers */ >> +/* Interrupt Registers - CAIA 1&2 */ >> static const cxl_p2n_reg_t CXL_PSL_DSISR_An = {0x060}; >> static const cxl_p2n_reg_t CXL_PSL_DAR_An = {0x068}; >> static const cxl_p2n_reg_t CXL_PSL_DSR_An = {0x070}; >> static const cxl_p2n_reg_t CXL_PSL_TFC_An = {0x078}; >> static const cxl_p2n_reg_t CXL_PSL_PEHandle_An = {0x080}; >> static const cxl_p2n_reg_t CXL_PSL_ErrStat_An = {0x088}; >> -/* AFU Registers */ >> +/* AFU Registers - CAIA 1&2 */ >> static const cxl_p2n_reg_t CXL_AFU_Cntl_An = {0x090}; >> static const cxl_p2n_reg_t CXL_AFU_ERR_An = {0x098}; >> -/* Work Element Descriptor */ >> +/* Work Element Descriptor - CAIA 1&2 */ >> static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; >> /* 0x0C0:FFF Implementation Dependent Area */ >> >> @@ -182,6 +201,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = >> {0x0A0}; >> #define CXL_PSL_SR_An_SF MSR_SF /* 64bit */ >> #define CXL_PSL_SR_An_TA (1ull << (63-1)) /* Tags active, GA1: 0 */ >> #define CXL_PSL_SR_An_HV MSR_HV /* Hypervisor, GA1: 0 */ >> +#define CXL_PSL_SR_An_XLAT_hpt (0ull << (63-6))/* Hashed page table >> (HPT) mode */ >> +#define CXL_PSL_SR_An_XLAT_roh (2ull << (63-6))/* Radix on HPT mode */ >> +#define CXL_PSL_SR_An_XLAT_ror (3ull << (63-6))/* Radix on Radix >> mode */ >> +#define CXL_PSL_SR_An_BOT (1ull << (63-10)) /* Use the in-memory >> segment table */ >> #define CXL_PSL_SR_An_PR MSR_PR /* Problem state, GA1: 1 */ >> #define CXL_PSL_SR_An_ISL (1ull << (63-53)) /* Ignore Segment Large >> Page */ >> #define CXL_PSL_SR_An_TC (1ull << (63-54)) /* Page Table secondary >> hash */ >> @@ -298,12 +321,38 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = >> {0x0A0}; >> #define CXL_PSL_DSISR_An_S DSISR_ISSTORE /* Access was afu_wr >> or afu_zero */ >> #define CXL_PSL_DSISR_An_K DSISR_KEYFAULT /* Access not >> permitted by virtual page class key protection */ >> >> +/****** CXL_PSL_DSISR_An - CAIA 2 >> ****************************************************/ >> +#define CXL_PSL9_DSISR_An_TF (1ull << (63-3)) /* Translation fault */ >> +#define CXL_PSL9_DSISR_An_PE (1ull << (63-4)) /* PSL Error >> (implementation specific) */ >> +#define CXL_PSL9_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ >> +#define CXL_PSL9_DSISR_An_OC (1ull << (63-6)) /* OS Context Warning */ >> +#define CXL_PSL9_DSISR_An_S (1ull << (63-38)) /* TF for a write >> operation */ >> +#define CXL_PSL9_DSISR_PENDING (CXL_PSL9_DSISR_An_TF | >> CXL_PSL9_DSISR_An_PE | CXL_PSL9_DSISR_An_AE | CXL_PSL9_DSISR_An_OC) >> +/* NOTE: Bits 56:63 (Checkout Response Status) are valid when >> DSISR_An[TF] = 1 >> + * Status (0:7) Encoding >> + */ >> +#define CXL_PSL9_DSISR_An_CO_MASK 0x00000000000000ffULL >> +#define CXL_PSL9_DSISR_An_SF 0x0000000000000080ULL /* Segment >> Fault 0b10000000 */ >> +#define CXL_PSL9_DSISR_An_PF_SLR 0x0000000000000088ULL /* PTE not >> found (Single Level Radix) 0b10001000 */ >> +#define CXL_PSL9_DSISR_An_PF_RGC 0x000000000000008CULL /* PTE not >> found (Radix Guest (child)) 0b10001100 */ >> +#define CXL_PSL9_DSISR_An_PF_RGP 0x0000000000000090ULL /* PTE not >> found (Radix Guest (parent)) 0b10010000 */ >> +#define CXL_PSL9_DSISR_An_PF_HRH 0x0000000000000094ULL /* PTE not >> found (HPT/Radix Host) 0b10010100 */ >> +#define CXL_PSL9_DSISR_An_PF_STEG 0x000000000000009CULL /* PTE not >> found (STEG VA) 0b10011100 */ >> + >> /****** CXL_PSL_TFC_An >> ******************************************************/ >> #define CXL_PSL_TFC_An_A (1ull << (63-28)) /* Acknowledge >> non-translation fault */ >> #define CXL_PSL_TFC_An_C (1ull << (63-29)) /* Continue (abort >> transaction) */ >> #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with >> address error */ >> #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL >> transaction */ >> >> +/****** CXL_XSL9_IERAT_ERAT - CAIA 2 >> **********************************/ >> +#define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */ >> +#define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */ >> +#define CXL_XSL9_IERAT_PRS (1ull << (63-4)) /* PRS bit for >> Radix invalidations */ >> +#define CXL_XSL9_IERAT_INVR (1ull << (63-3)) /* Invalidate >> Radix */ >> +#define CXL_XSL9_IERAT_IALL (1ull << (63-8)) /* Invalidate All */ >> +#define CXL_XSL9_IERAT_IINPROG (1ull << (63-63)) /* Invalidate in >> progress */ >> + >> /* cxl_process_element->software_status */ >> #define CXL_PE_SOFTWARE_STATE_V (1ul << (31 - 0)) /* Valid */ >> #define CXL_PE_SOFTWARE_STATE_C (1ul << (31 - 29)) /* Complete */ >> @@ -654,25 +703,38 @@ int cxl_pci_reset(struct cxl *adapter); >> void cxl_pci_release_afu(struct device *dev); >> ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, >> size_t len); >> >> -/* common == phyp + powernv */ >> +/* common == phyp + powernv - CAIA 1&2 */ >> struct cxl_process_element_common { >> __be32 tid; >> __be32 pid; >> __be64 csrp; >> - __be64 aurp0; >> - __be64 aurp1; >> - __be64 sstp0; >> - __be64 sstp1; >> + union { >> + struct { >> + __be64 aurp0; >> + __be64 aurp1; >> + __be64 sstp0; >> + __be64 sstp1; >> + } psl8; /* CAIA 1 */ >> + struct { >> + u8 reserved2[8]; >> + u8 reserved3[8]; >> + u8 reserved4[8]; >> + u8 reserved5[8]; >> + } psl9; /* CAIA 2 */ >> + } u; >> __be64 amr; >> - u8 reserved3[4]; >> + u8 reserved6[4]; >> __be64 wed; >> } __packed; >> >> -/* just powernv */ >> +/* just powernv - CAIA 1&2 */ >> struct cxl_process_element { >> __be64 sr; >> __be64 SPOffset; >> - __be64 sdr; >> + union { >> + __be64 sdr; /* CAIA 1 */ >> + u8 reserved1[8]; /* CAIA 2 */ >> + } u; >> __be64 haurp; >> __be32 ctxtime; >> __be16 ivte_offsets[4]; >> @@ -761,6 +823,16 @@ static inline bool cxl_is_power8(void) >> return false; >> } >> >> +static inline bool cxl_is_power9(void) >> +{ >> + /* intermediate solution */ >> + if (!cxl_is_power8() && >> + (cpu_has_feature(CPU_FTRS_POWER9) || >> + cpu_has_feature(CPU_FTR_POWER9_DD1))) >> + return true; >> + return false; >> +} >> + >> static inline bool cxl_is_psl8(struct cxl_afu *afu) >> { >> if (afu->adapter->caia_major == 1) >> @@ -768,6 +840,13 @@ static inline bool cxl_is_psl8(struct cxl_afu *afu) >> return false; >> } >> >> +static inline bool cxl_is_psl9(struct cxl_afu *afu) >> +{ >> + if (afu->adapter->caia_major == 2) >> + return true; >> + return false; >> +} >> + >> ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, >> loff_t off, size_t count); >> >> @@ -794,7 +873,6 @@ int cxl_update_properties(struct device_node *dn, >> struct property *new_prop); >> >> void cxl_remove_adapter_nr(struct cxl *adapter); >> >> -int cxl_alloc_spa(struct cxl_afu *afu); >> void cxl_release_spa(struct cxl_afu *afu); >> >> dev_t cxl_get_dev(void); >> @@ -832,9 +910,13 @@ int afu_register_irqs(struct cxl_context *ctx, >> u32 count); >> void afu_release_irqs(struct cxl_context *ctx, void *cookie); >> void afu_irq_name_free(struct cxl_context *ctx); >> >> +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, >> u64 amr); >> int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, >> u64 amr); >> +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu); >> int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu); >> +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 >> wed, u64 amr); >> int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 >> wed, u64 amr); >> +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx); >> void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx); >> >> #ifdef CONFIG_DEBUG_FS >> @@ -845,9 +927,12 @@ int cxl_debugfs_adapter_add(struct cxl *adapter); >> void cxl_debugfs_adapter_remove(struct cxl *adapter); >> int cxl_debugfs_afu_add(struct cxl_afu *afu); >> void cxl_debugfs_afu_remove(struct cxl_afu *afu); >> +void cxl_stop_trace_psl9(struct cxl *cxl); >> void cxl_stop_trace_psl8(struct cxl *cxl); >> +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct >> dentry *dir); >> void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct >> dentry *dir); >> void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, struct >> dentry *dir); >> +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct >> dentry *dir); >> void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct >> dentry *dir); >> >> #else /* CONFIG_DEBUG_FS */ >> @@ -879,10 +964,19 @@ static inline void >> cxl_debugfs_afu_remove(struct cxl_afu *afu) >> { >> } >> >> +static inline void cxl_stop_trace_psl9(struct cxl *cxl) >> +{ >> +} >> + >> static inline void cxl_stop_trace_psl8(struct cxl *cxl) >> { >> } >> >> +static inline void cxl_debugfs_add_adapter_regs_psl9(struct cxl >> *adapter, >> + struct dentry *dir) >> +{ >> +} >> + >> static inline void cxl_debugfs_add_adapter_regs_psl8(struct cxl >> *adapter, >> struct dentry *dir) >> { >> @@ -893,6 +987,10 @@ static inline void >> cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, >> { >> } >> >> +static inline void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu >> *afu, struct dentry *dir) >> +{ >> +} >> + >> static inline void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu >> *afu, struct dentry *dir) >> { >> } >> @@ -951,7 +1049,9 @@ struct cxl_irq_info { >> }; >> >> void cxl_assign_psn_space(struct cxl_context *ctx); >> +int cxl_invalidate_all_psl9(struct cxl *adapter); >> int cxl_invalidate_all_psl8(struct cxl *adapter); >> +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct >> cxl_irq_info *irq_info); >> irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct >> cxl_irq_info *irq_info); >> irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct >> cxl_irq_info *irq_info); >> int cxl_register_one_irq(struct cxl *adapter, irq_handler_t handler, >> @@ -964,6 +1064,7 @@ int cxl_data_cache_flush(struct cxl *adapter); >> int cxl_afu_disable(struct cxl_afu *afu); >> int cxl_psl_purge(struct cxl_afu *afu); >> >> +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx); >> void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx); >> void cxl_native_err_irq_dump_regs(struct cxl *adapter); >> int cxl_pci_vphb_add(struct cxl_afu *afu); >> diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c >> index 43a1a27..eae9d74 100644 >> --- a/drivers/misc/cxl/debugfs.c >> +++ b/drivers/misc/cxl/debugfs.c >> @@ -15,6 +15,12 @@ >> >> static struct dentry *cxl_debugfs; >> >> +void cxl_stop_trace_psl9(struct cxl *adapter) >> +{ >> + /* Stop the trace */ >> + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x4480000000000000ULL); >> +} >> + >> void cxl_stop_trace_psl8(struct cxl *adapter) >> { >> int slice; >> @@ -53,6 +59,14 @@ static struct dentry *debugfs_create_io_x64(const >> char *name, umode_t mode, >> (void __force *)value, &fops_io_x64); >> } >> >> +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct >> dentry *dir) >> +{ >> + debugfs_create_io_x64("fir1", S_IRUSR, dir, >> _cxl_p1_addr(adapter, CXL_PSL9_FIR1)); >> + debugfs_create_io_x64("fir2", S_IRUSR, dir, >> _cxl_p1_addr(adapter, CXL_PSL9_FIR2)); >> + debugfs_create_io_x64("fir_cntl", S_IRUSR, dir, >> _cxl_p1_addr(adapter, CXL_PSL9_FIR_CNTL)); >> + debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, >> _cxl_p1_addr(adapter, CXL_PSL9_TRACECFG)); >> +} >> + >> void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct >> dentry *dir) >> { >> debugfs_create_io_x64("fir1", S_IRUSR, dir, >> _cxl_p1_addr(adapter, CXL_PSL_FIR1)); >> @@ -92,6 +106,11 @@ void cxl_debugfs_adapter_remove(struct cxl *adapter) >> debugfs_remove_recursive(adapter->debugfs); >> } >> >> +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct >> dentry *dir) >> +{ >> + debugfs_create_io_x64("serr", S_IRUSR, dir, _cxl_p1n_addr(afu, >> CXL_PSL_SERR_An)); >> +} >> + >> void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct >> dentry *dir) >> { >> debugfs_create_io_x64("sstp0", S_IRUSR, dir, _cxl_p2n_addr(afu, >> CXL_SSTP0_An)); >> diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c >> index f24c15c..381ae70 100644 >> --- a/drivers/misc/cxl/fault.c >> +++ b/drivers/misc/cxl/fault.c >> @@ -146,25 +146,26 @@ static void cxl_handle_page_fault(struct >> cxl_context *ctx, >> return cxl_ack_ae(ctx); >> } >> >> - /* >> - * update_mmu_cache() will not have loaded the hash since >> current->trap >> - * is not a 0x400 or 0x300, so just call hash_page_mm() here. >> - */ >> - access = _PAGE_PRESENT | _PAGE_READ; >> - if (dsisr & CXL_PSL_DSISR_An_S) >> - access |= _PAGE_WRITE; >> - >> - access |= _PAGE_PRIVILEGED; >> - if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) >> - access &= ~_PAGE_PRIVILEGED; >> - >> - if (dsisr & DSISR_NOHPTE) >> - inv_flags |= HPTE_NOHPTE_UPDATE; >> - >> - local_irq_save(flags); >> - hash_page_mm(mm, dar, access, 0x300, inv_flags); >> - local_irq_restore(flags); >> - >> + if (!radix_enabled()) { >> + /* >> + * update_mmu_cache() will not have loaded the hash since >> current->trap >> + * is not a 0x400 or 0x300, so just call hash_page_mm() here. >> + */ >> + access = _PAGE_PRESENT | _PAGE_READ; >> + if (dsisr & CXL_PSL_DSISR_An_S) >> + access |= _PAGE_WRITE; >> + >> + access |= _PAGE_PRIVILEGED; >> + if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) >> + access &= ~_PAGE_PRIVILEGED; >> + >> + if (dsisr & DSISR_NOHPTE) >> + inv_flags |= HPTE_NOHPTE_UPDATE; >> + >> + local_irq_save(flags); >> + hash_page_mm(mm, dar, access, 0x300, inv_flags); >> + local_irq_restore(flags); >> + } >> pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe); >> cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0); >> } >> @@ -179,12 +180,33 @@ static struct mm_struct *get_mem_context(struct >> cxl_context *ctx) >> return NULL; >> >> if (!atomic_inc_not_zero(&ctx->mm->mm_users)) >> - return ctx->mm; >> + return NULL; >> >> - return NULL; >> + return ctx->mm; >> } > > > This looks wrong... I think the previous version was correct. Either > way, only one code change should be enough. > > If mm_users had gone to zero, that assumes the context may be in the process of being closed, so a NULL value has to be returned. atomic_inc_not_zero non-zero if mm_users was non-zero. Otherwise, you are right only one code change should be enough. > >> >> +static bool cxl_is_segment_miss(struct cxl_context *ctx, u64 dsisr) >> +{ >> + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DS)) >> + return true; >> >> + return false; >> +} >> + >> +static bool cxl_is_page_fault(struct cxl_context *ctx, u64 dsisr) >> +{ >> + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DM)) >> + return true; >> + >> + if ((cxl_is_psl9(ctx->afu)) && >> + ((dsisr & CXL_PSL9_DSISR_An_CO_MASK) & >> + (CXL_PSL9_DSISR_An_PF_SLR | CXL_PSL9_DSISR_An_PF_RGC | >> + CXL_PSL9_DSISR_An_PF_RGP | CXL_PSL9_DSISR_An_PF_HRH | >> + CXL_PSL9_DSISR_An_PF_STEG))) >> + return true; >> + >> + return false; >> +} >> >> void cxl_handle_fault(struct work_struct *fault_work) >> { >> @@ -230,14 +252,12 @@ void cxl_handle_fault(struct work_struct >> *fault_work) >> } >> } >> >> - if (cxl_is_psl8(ctx->afu)) { >> - if (dsisr & CXL_PSL_DSISR_An_DS) >> - cxl_handle_segment_miss(ctx, mm, dar); >> - else if (dsisr & CXL_PSL_DSISR_An_DM) >> - cxl_handle_page_fault(ctx, mm, dsisr, dar); >> - else >> - WARN(1, "cxl_handle_fault has nothing to handle\n"); >> - } >> + if (cxl_is_segment_miss(ctx, dsisr)) >> + cxl_handle_segment_miss(ctx, mm, dar); >> + else if (cxl_is_page_fault(ctx, dsisr)) >> + cxl_handle_page_fault(ctx, mm, dsisr, dar); >> + else >> + WARN(1, "cxl_handle_fault has nothing to handle\n"); >> >> if (mm) >> mmput(mm); >> diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c >> index 3ad7381..f58b4b6c 100644 >> --- a/drivers/misc/cxl/guest.c >> +++ b/drivers/misc/cxl/guest.c >> @@ -551,13 +551,13 @@ static int attach_afu_directed(struct >> cxl_context *ctx, u64 wed, u64 amr) >> elem->common.tid = cpu_to_be32(0); /* Unused */ >> elem->common.pid = cpu_to_be32(pid); >> elem->common.csrp = cpu_to_be64(0); /* disable */ >> - elem->common.aurp0 = cpu_to_be64(0); /* disable */ >> - elem->common.aurp1 = cpu_to_be64(0); /* disable */ >> + elem->common.u.psl8.aurp0 = cpu_to_be64(0); /* disable */ >> + elem->common.u.psl8.aurp1 = cpu_to_be64(0); /* disable */ >> >> cxl_prefault(ctx, wed); >> >> - elem->common.sstp0 = cpu_to_be64(ctx->sstp0); >> - elem->common.sstp1 = cpu_to_be64(ctx->sstp1); >> + elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); >> + elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); >> >> /* >> * Ensure we have at least one interrupt allocated to take >> faults for >> diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c >> index fa9f8a2..1eb5168 100644 >> --- a/drivers/misc/cxl/irq.c >> +++ b/drivers/misc/cxl/irq.c >> @@ -34,6 +34,59 @@ static irqreturn_t schedule_cxl_fault(struct >> cxl_context *ctx, u64 dsisr, u64 da >> return IRQ_HANDLED; >> } >> >> +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct >> cxl_irq_info *irq_info) >> +{ >> + u64 dsisr, dar; >> + >> + dsisr = irq_info->dsisr; >> + dar = irq_info->dar; >> + >> + trace_cxl_psl9_irq(ctx, irq, dsisr, dar); >> + >> + pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: >> %#llx\n", irq, ctx->pe, dsisr, dar); >> + >> + if (dsisr & CXL_PSL9_DSISR_An_TF) { >> + pr_devel("CXL interrupt: Scheduling translation fault" >> + " handling for later (pe: %i)\n", ctx->pe); >> + return schedule_cxl_fault(ctx, dsisr, dar); >> + } >> + >> + if (dsisr & CXL_PSL9_DSISR_An_PE) >> + return cxl_ops->handle_psl_slice_error(ctx, dsisr, >> + irq_info->errstat); >> + if (dsisr & CXL_PSL9_DSISR_An_AE) { >> + pr_devel("CXL interrupt: AFU Error 0x%016llx\n", >> irq_info->afu_err); >> + >> + if (ctx->pending_afu_err) { >> + /* >> + * This shouldn't happen - the PSL treats these errors >> + * as fatal and will have reset the AFU, so there's not >> + * much point buffering multiple AFU errors. >> + * OTOH if we DO ever see a storm of these come in it's >> + * probably best that we log them somewhere: >> + */ >> + dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " >> + "undelivered to pe %i: 0x%016llx\n", >> + ctx->pe, irq_info->afu_err); >> + } else { >> + spin_lock(&ctx->lock); >> + ctx->afu_err = irq_info->afu_err; >> + ctx->pending_afu_err = 1; >> + spin_unlock(&ctx->lock); >> + >> + wake_up_all(&ctx->wq); >> + } >> + >> + cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_A, 0); >> + return IRQ_HANDLED; >> + } >> + if (dsisr & CXL_PSL9_DSISR_An_OC) >> + pr_devel("CXL interrupt: OS Context Warning\n"); >> + >> + WARN(1, "Unhandled CXL PSL IRQ\n"); >> + return IRQ_HANDLED; >> +} >> + >> irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct >> cxl_irq_info *irq_info) >> { >> u64 dsisr, dar; >> diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c >> index 7b86ffa..67c9bc6 100644 >> --- a/drivers/misc/cxl/native.c >> +++ b/drivers/misc/cxl/native.c >> @@ -120,6 +120,7 @@ int cxl_psl_purge(struct cxl_afu *afu) >> u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); >> u64 dsisr, dar; >> u64 start, end; >> + u64 trans_fault = 0x0ULL; >> unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); >> int rc = 0; >> >> @@ -127,6 +128,11 @@ int cxl_psl_purge(struct cxl_afu *afu) >> >> pr_devel("PSL purge request\n"); >> >> + if (cxl_is_psl8(afu)) >> + trans_fault = CXL_PSL_DSISR_TRANS; >> + if (cxl_is_psl9(afu)) >> + trans_fault = CXL_PSL9_DSISR_An_TF; >> + >> if (!cxl_ops->link_ok(afu->adapter, afu)) { >> dev_warn(&afu->dev, "PSL Purge called with link down, >> ignoring\n"); >> rc = -EIO; >> @@ -158,22 +164,21 @@ int cxl_psl_purge(struct cxl_afu *afu) >> pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx" >> " PSL_DSISR: 0x%016llx\n", >> PSL_CNTL, dsisr); >> - if (cxl_is_psl8(afu)) { >> - if (dsisr & CXL_PSL_DSISR_TRANS) { >> - dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); >> - dev_notice(&afu->dev, "PSL purge terminating " >> - "pending translation, " >> - "DSISR: 0x%016llx, DAR: 0x%016llx\n", >> - dsisr, dar); >> - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); >> - } else if (dsisr) { >> - dev_notice(&afu->dev, "PSL purge acknowledging " >> - "pending non-translation fault, " >> - "DSISR: 0x%016llx\n", dsisr); >> - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); >> - } else { >> - cpu_relax(); >> - } >> + >> + if (dsisr & trans_fault) { >> + dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); >> + dev_notice(&afu->dev, "PSL purge terminating " >> + "pending translation, " >> + "DSISR: 0x%016llx, DAR: 0x%016llx\n", >> + dsisr, dar); >> + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); >> + } else if (dsisr) { >> + dev_notice(&afu->dev, "PSL purge acknowledging " >> + "pending non-translation fault, " >> + "DSISR: 0x%016llx\n", dsisr); >> + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); >> + } else { >> + cpu_relax(); >> } >> PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An); >> } >> @@ -205,7 +210,7 @@ static int spa_max_procs(int spa_size) >> return ((spa_size / 8) - 96) / 17; >> } >> >> -int cxl_alloc_spa(struct cxl_afu *afu) >> +static int cxl_alloc_spa(struct cxl_afu *afu, int mode) >> { >> unsigned spa_size; >> >> @@ -218,7 +223,8 @@ int cxl_alloc_spa(struct cxl_afu *afu) >> if (spa_size > 0x100000) { >> dev_warn(&afu->dev, "num_of_processes too large for the >> SPA, limiting to %i (0x%x)\n", >> afu->native->spa_max_procs, afu->native->spa_size); >> - afu->num_procs = afu->native->spa_max_procs; >> + if (mode != CXL_MODE_DEDICATED) >> + afu->num_procs = afu->native->spa_max_procs; >> break; >> } >> >> @@ -267,6 +273,35 @@ void cxl_release_spa(struct cxl_afu *afu) >> } >> } >> >> +/* Invalidation of all ERAT entries is no longer required by CAIA2. Use >> + * only for debug >> + */ >> +int cxl_invalidate_all_psl9(struct cxl *adapter) >> +{ >> + unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); >> + u64 ierat; >> + >> + pr_devel("CXL adapter - invalidation of all ERAT entries\n"); >> + >> + /* Invalidates all ERAT entries for Radix or HPT */ >> + ierat = CXL_XSL9_IERAT_IALL; >> + if (radix_enabled()) >> + ierat |= CXL_XSL9_IERAT_INVR; >> + cxl_p1_write(adapter, CXL_XSL9_IERAT, ierat); >> + >> + while (cxl_p1_read(adapter, CXL_XSL9_IERAT) & >> CXL_XSL9_IERAT_IINPROG) { >> + if (time_after_eq(jiffies, timeout)) { >> + dev_warn(&adapter->dev, >> + "WARNING: CXL adapter invalidation of all ERAT entries >> timed out!\n"); >> + return -EBUSY; >> + } >> + if (!cxl_ops->link_ok(adapter, NULL)) >> + return -EIO; >> + cpu_relax(); >> + } >> + return 0; >> +} >> + >> int cxl_invalidate_all_psl8(struct cxl *adapter) >> { >> unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); >> @@ -503,7 +538,7 @@ static int activate_afu_directed(struct cxl_afu >> *afu) >> >> afu->num_procs = afu->max_procs_virtualised; >> if (afu->native->spa == NULL) { >> - if (cxl_alloc_spa(afu)) >> + if (cxl_alloc_spa(afu, CXL_MODE_DIRECTED)) >> return -ENOMEM; >> } >> attach_spa(afu); >> @@ -553,10 +588,19 @@ static u64 calculate_sr(struct cxl_context *ctx) >> sr |= (mfmsr() & MSR_SF) | CXL_PSL_SR_An_HV; >> } else { >> sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R; >> - sr &= ~(CXL_PSL_SR_An_HV); >> + if (radix_enabled()) >> + sr |= CXL_PSL_SR_An_HV; >> + else >> + sr &= ~(CXL_PSL_SR_An_HV); >> if (!test_tsk_thread_flag(current, TIF_32BIT)) >> sr |= CXL_PSL_SR_An_SF; >> } >> + if (cxl_is_psl9(ctx->afu)) { >> + if (radix_enabled()) >> + sr |= CXL_PSL_SR_An_XLAT_ror; >> + else >> + sr |= CXL_PSL_SR_An_XLAT_hpt; >> + } >> return sr; >> } >> >> @@ -589,6 +633,70 @@ static void update_ivtes_directed(struct >> cxl_context *ctx) >> WARN_ON(add_process_element(ctx)); >> } >> >> +static int process_element_entry(struct cxl_context *ctx, u64 wed, >> u64 amr) > > > Could we have a "9" in the name, to show that's it's only used for psl9? > I was actually wondering if we could refactor to also use it on psl8, > but it seems that's there's enough low-level details being different > that it's ok to keep the 2 version separate. > > okay to rename process_element_entry() to process_element_entry_psl9() >> +{ >> + u32 pid; >> + >> + cxl_assign_psn_space(ctx); >> + >> + ctx->elem->ctxtime = 0; /* disable */ >> + ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); >> + ctx->elem->haurp = 0; /* disable */ >> + >> + if (ctx->kernel) >> + pid = 0; >> + else { >> + if (ctx->mm == NULL) { >> + pr_devel("%s: unable to get mm for pe=%d pid=%i\n", >> + __func__, ctx->pe, pid_nr(ctx->pid)); >> + return -EINVAL; >> + } >> + pid = ctx->mm->context.id; >> + } >> + >> + ctx->elem->common.tid = 0; >> + ctx->elem->common.pid = cpu_to_be32(pid); >> + >> + ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); >> + >> + ctx->elem->common.csrp = 0; /* disable */ >> + >> + cxl_prefault(ctx, wed); >> + >> + /* >> + * Ensure we have the multiplexed PSL interrupt set up to take >> faults >> + * for kernel contexts that may not have allocated any AFU IRQs >> at all: >> + */ >> + if (ctx->irqs.range[0] == 0) { >> + ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq; >> + ctx->irqs.range[0] = 1; >> + } >> + >> + ctx->elem->common.amr = cpu_to_be64(amr); >> + ctx->elem->common.wed = cpu_to_be64(wed); >> + >> + return 0; >> +} >> + >> +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, >> u64 amr) >> +{ >> + int result; >> + >> + /* fill the process element entry */ >> + result = process_element_entry(ctx, wed, amr); >> + if (result) >> + return result; >> + >> + update_ivtes_directed(ctx); >> + >> + /* first guy needs to enable */ >> + result = cxl_ops->afu_check_and_enable(ctx->afu); >> + if (result) >> + return result; >> + >> + return add_process_element(ctx); >> +} >> + >> int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, >> u64 amr) >> { >> u32 pid; >> @@ -599,7 +707,7 @@ int cxl_attach_afu_directed_psl8(struct >> cxl_context *ctx, u64 wed, u64 amr) >> ctx->elem->ctxtime = 0; /* disable */ >> ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); >> ctx->elem->haurp = 0; /* disable */ >> - ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1)); >> + ctx->elem->u.sdr = cpu_to_be64(mfspr(SPRN_SDR1)); >> >> pid = current->pid; >> if (ctx->kernel) >> @@ -610,13 +718,13 @@ int cxl_attach_afu_directed_psl8(struct >> cxl_context *ctx, u64 wed, u64 amr) >> ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); >> >> ctx->elem->common.csrp = 0; /* disable */ >> - ctx->elem->common.aurp0 = 0; /* disable */ >> - ctx->elem->common.aurp1 = 0; /* disable */ >> + ctx->elem->common.u.psl8.aurp0 = 0; /* disable */ >> + ctx->elem->common.u.psl8.aurp1 = 0; /* disable */ >> >> cxl_prefault(ctx, wed); >> >> - ctx->elem->common.sstp0 = cpu_to_be64(ctx->sstp0); >> - ctx->elem->common.sstp1 = cpu_to_be64(ctx->sstp1); >> + ctx->elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); >> + ctx->elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); >> >> /* >> * Ensure we have the multiplexed PSL interrupt set up to take >> faults >> @@ -682,6 +790,31 @@ static int deactivate_afu_directed(struct >> cxl_afu *afu) >> return 0; >> } >> >> +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu) >> +{ >> + dev_info(&afu->dev, "Activating dedicated process mode\n"); >> + >> + /* If XSL is set to dedicated mode (Set in PSL_SCNTL reg), the >> + * XSL and AFU are programmed to work with a single context. >> + * The context information should be configured in the SPA area >> + * index 0 (so PSL_SPAP must be configured before enabling the >> + * AFU). >> + */ >> + afu->num_procs = 1; >> + if (afu->native->spa == NULL) { >> + if (cxl_alloc_spa(afu, CXL_MODE_DEDICATED)) >> + return -ENOMEM; >> + } >> + attach_spa(afu); >> + >> + cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process); >> + cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | >> CXL_PSL_ID_An_L); >> + >> + afu->current_mode = CXL_MODE_DEDICATED; >> + >> + return cxl_chardev_d_afu_add(afu); >> +} >> + >> int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu) >> { >> dev_info(&afu->dev, "Activating dedicated process mode\n"); >> @@ -705,6 +838,16 @@ int cxl_activate_dedicated_process_psl8(struct >> cxl_afu *afu) >> return cxl_chardev_d_afu_add(afu); >> } >> >> +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx) >> +{ >> + int r; >> + >> + for (r = 0; r < CXL_IRQ_RANGES; r++) { >> + ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]); >> + ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]); >> + } >> +} >> + >> void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx) >> { >> struct cxl_afu *afu = ctx->afu; >> @@ -721,6 +864,26 @@ void cxl_update_dedicated_ivtes_psl8(struct >> cxl_context *ctx) >> ((u64)ctx->irqs.range[3] & 0xffff)); >> } >> >> +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 >> wed, u64 amr) >> +{ >> + struct cxl_afu *afu = ctx->afu; >> + int result; >> + >> + /* fill the process element entry */ >> + result = process_element_entry(ctx, wed, amr); >> + if (result) >> + return result; >> + >> + if (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes) >> + afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx); >> + >> + result = cxl_ops->afu_reset(afu); >> + if (result) >> + return result; >> + >> + return afu_enable(afu); >> +} >> + >> int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 >> wed, u64 amr) >> { >> struct cxl_afu *afu = ctx->afu; >> @@ -892,6 +1055,21 @@ static int native_get_irq_info(struct cxl_afu >> *afu, struct cxl_irq_info *info) >> return 0; >> } >> >> +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx) >> +{ >> + u64 fir1, fir2, serr; >> + >> + fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR1); >> + fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR2); >> + >> + dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); >> + dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); >> + if (ctx->afu->adapter->native->sl_ops->register_serr_irq) { >> + serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); >> + cxl_afu_decode_psl_serr(ctx->afu, serr); >> + } >> +} >> + >> void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx) >> { >> u64 fir1, fir2, fir_slice, serr, afu_debug; >> @@ -928,9 +1106,20 @@ static irqreturn_t >> native_handle_psl_slice_error(struct cxl_context *ctx, >> return cxl_ops->ack_irq(ctx, 0, errstat); >> } >> >> +static bool cxl_is_translation_fault(struct cxl_afu *afu, u64 dsisr) >> +{ >> + if ((cxl_is_psl8(afu)) && (dsisr & CXL_PSL_DSISR_TRANS)) >> + return true; >> + >> + if ((cxl_is_psl9(afu)) && (dsisr & CXL_PSL9_DSISR_An_TF)) >> + return true; >> + >> + return false; >> +} >> + >> irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct >> cxl_irq_info *irq_info) >> { >> - if (irq_info->dsisr & CXL_PSL_DSISR_TRANS) >> + if (cxl_is_translation_fault(afu, irq_info->dsisr)) >> cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); >> else >> cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); >> @@ -1001,6 +1190,9 @@ static void native_irq_wait(struct cxl_context >> *ctx) >> if (cxl_is_psl8(ctx->afu) && >> ((dsisr & CXL_PSL_DSISR_PENDING) == 0)) >> return; >> + if (cxl_is_psl9(ctx->afu) && >> + ((dsisr & CXL_PSL9_DSISR_PENDING) == 0)) >> + return; >> /* >> * We are waiting for the workqueue to process our >> * irq, so need to let that run here. >> @@ -1127,8 +1319,7 @@ int cxl_native_register_serr_irq(struct cxl_afu >> *afu) >> } >> >> serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); >> - if (cxl_is_power8()) >> - serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & >> 0xffff); >> + serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); > > > This looks wrong. Previous version was setting the SERR differently on > p9, since some errors are masked by default. So it looks like the > above is not correct? > > Fred > > > good point > >> cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); >> >> return 0; >> diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c >> index 360c231..428c80b 100644 >> --- a/drivers/misc/cxl/pci.c >> +++ b/drivers/misc/cxl/pci.c >> @@ -60,7 +60,7 @@ >> #define CXL_VSEC_PROTOCOL_MASK 0xe0 >> #define CXL_VSEC_PROTOCOL_1024TB 0x80 >> #define CXL_VSEC_PROTOCOL_512TB 0x40 >> -#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8 uses this */ >> +#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8/9 uses this */ >> #define CXL_VSEC_PROTOCOL_ENABLE 0x01 >> >> #define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \ >> @@ -326,14 +326,20 @@ static void dump_afu_descriptor(struct cxl_afu >> *afu) >> >> #define P8_CAPP_UNIT0_ID 0xBA >> #define P8_CAPP_UNIT1_ID 0XBE >> +#define P9_CAPP_UNIT0_ID 0xC0 >> +#define P9_CAPP_UNIT1_ID 0xE0 >> >> -static u64 get_capp_unit_id(struct device_node *np) >> +static u32 get_phb_index(struct device_node *np) >> { >> u32 phb_index; >> >> if (of_property_read_u32(np, "ibm,phb-index", &phb_index)) >> - return 0; >> + return -ENODEV; >> + return phb_index; >> +} >> >> +static u64 get_capp_unit_id(struct device_node *np, u32 phb_index) >> +{ >> /* >> * POWER 8: >> * - For chips other than POWER8NVL, we only have CAPP 0, >> @@ -352,10 +358,25 @@ static u64 get_capp_unit_id(struct device_node >> *np) >> return P8_CAPP_UNIT1_ID; >> } >> >> + /* >> + * POWER 9: >> + * PEC0 (PHB0). Capp ID = CAPP0 (0b1100_0000) >> + * PEC1 (PHB1 - PHB2). No capi mode >> + * PEC2 (PHB3 - PHB4 - PHB5): Capi mode on PHB3 only. Capp ID >> = CAPP1 (0b1110_0000) >> + */ >> + if (cxl_is_power9()) { >> + if (phb_index == 0) >> + return P9_CAPP_UNIT0_ID; >> + >> + if (phb_index == 3) >> + return P9_CAPP_UNIT1_ID; >> + } >> + >> return 0; >> } >> >> -static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 >> *capp_unit_id) >> +static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, >> + u32 *phb_index, u64 *capp_unit_id) >> { >> struct device_node *np; >> const __be32 *prop; >> @@ -367,8 +388,16 @@ static int calc_capp_routing(struct pci_dev >> *dev, u64 *chipid, u64 *capp_unit_id >> np = of_get_next_parent(np); >> if (!np) >> return -ENODEV; >> + >> *chipid = be32_to_cpup(prop); >> - *capp_unit_id = get_capp_unit_id(np); >> + >> + *phb_index = get_phb_index(np); >> + if (*phb_index == -ENODEV) { >> + pr_err("cxl: invalid phb index\n"); >> + return -ENODEV; >> + } >> + >> + *capp_unit_id = get_capp_unit_id(np, *phb_index); >> of_node_put(np); >> if (!*capp_unit_id) { >> pr_err("cxl: invalid capp unit id\n"); >> @@ -378,14 +407,97 @@ static int calc_capp_routing(struct pci_dev >> *dev, u64 *chipid, u64 *capp_unit_id >> return 0; >> } >> >> +static int init_implementation_adapter_regs_psl9(struct cxl >> *adapter, struct pci_dev *dev) >> +{ >> + u64 xsl_dsnctl, psl_fircntl; >> + u64 chipid; >> + u32 phb_index; >> + u64 capp_unit_id; >> + int rc; >> + >> + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); >> + if (rc) >> + return rc; >> + >> + /* CAPI Identifier bits [0:7] >> + * bit 61:60 MSI bits --> 0 >> + * bit 59 TVT selector --> 0 >> + */ >> + /* Tell XSL where to route data to. >> + * The field chipid should match the PHB CAPI_CMPM register >> + */ >> + xsl_dsnctl = ((u64)0x2 << (63-7)); /* Bit 57 */ >> + xsl_dsnctl |= (capp_unit_id << (63-15)); >> + >> + /* nMMU_ID Defaults to: b’000001001’*/ >> + xsl_dsnctl |= ((u64)0x09 << (63-28)); >> + >> + if (cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)) { >> + /* Used to identify CAPI packets which should be sorted into >> + * the Non-Blocking queues by the PHB. This field should match >> + * the PHB PBL_NBW_CMPM register >> + * nbwind=0x03, bits [57:58], must include capi indicator. >> + * Not supported on P9 DD1. >> + */ >> + xsl_dsnctl |= ((u64)0x03 << (63-47)); >> + >> + /* Upper 16b address bits of ASB_Notify messages sent to the >> + * system. Need to match the PHB’s ASN Compare/Mask Register. >> + * Not supported on P9 DD1. >> + */ >> + xsl_dsnctl |= ((u64)0x04 << (63-55)); >> + } >> + >> + cxl_p1_write(adapter, CXL_XSL9_DSNCTL, xsl_dsnctl); >> + >> + /* Set fir_cntl to recommended value for production env */ >> + psl_fircntl = (0x2ULL << (63-3)); /* ce_report */ >> + psl_fircntl |= (0x1ULL << (63-6)); /* FIR_report */ >> + psl_fircntl |= 0x1ULL; /* ce_thresh */ >> + cxl_p1_write(adapter, CXL_PSL9_FIR_CNTL, psl_fircntl); >> + >> + /* vccredits=0x1 pcklat=0x4 */ >> + cxl_p1_write(adapter, CXL_PSL9_DSNDCTL, 0x0000000000001810ULL); >> + >> + /* For debugging with trace arrays. >> + * Configure RX trace 0 segmented mode. >> + * Configure CT trace 0 segmented mode. >> + * Configure LA0 trace 0 segmented mode. >> + * Configure LA1 trace 0 segmented mode. >> + */ >> + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000000ULL); >> + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000003ULL); >> + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000005ULL); >> + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000006ULL); >> + >> + /* A response to an ASB_Notify request is returned by the >> + * system as an MMIO write to the address defined in >> + * the PSL_TNR_ADDR register >> + */ >> + /* PSL_TNR_ADDR */ >> + >> + /* NORST */ >> + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL); >> + >> + /* allocate the apc machines */ >> + cxl_p1_write(adapter, CXL_PSL9_APCDEDTYPE, 0x40000003FFFF0000ULL); >> + >> + /* Disable vc dd1 fix */ >> + if ((cxl_is_power9() && cpu_has_feature(CPU_FTR_POWER9_DD1))) >> + cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0400000000000001ULL); >> + >> + return 0; >> +} >> + >> static int init_implementation_adapter_regs_psl8(struct cxl >> *adapter, struct pci_dev *dev) >> { >> u64 psl_dsnctl, psl_fircntl; >> u64 chipid; >> + u32 phb_index; >> u64 capp_unit_id; >> int rc; >> >> - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); >> + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); >> if (rc) >> return rc; >> >> @@ -414,10 +526,11 @@ static int >> init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ >> { >> u64 xsl_dsnctl; >> u64 chipid; >> + u32 phb_index; >> u64 capp_unit_id; >> int rc; >> >> - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); >> + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); >> if (rc) >> return rc; >> >> @@ -435,6 +548,12 @@ static int >> init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ >> /* For the PSL this is a multiple for 0 < n <= 7: */ >> #define PSL_2048_250MHZ_CYCLES 1 >> >> +static void write_timebase_ctrl_psl9(struct cxl *adapter) >> +{ >> + cxl_p1_write(adapter, CXL_PSL9_TB_CTLSTAT, >> + TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES)); >> +} >> + >> static void write_timebase_ctrl_psl8(struct cxl *adapter) >> { >> cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT, >> @@ -456,6 +575,11 @@ static void write_timebase_ctrl_xsl(struct cxl >> *adapter) >> TBSYNC_CNT(XSL_4000_CLOCKS)); >> } >> >> +static u64 timebase_read_psl9(struct cxl *adapter) >> +{ >> + return cxl_p1_read(adapter, CXL_PSL9_Timebase); >> +} >> + >> static u64 timebase_read_psl8(struct cxl *adapter) >> { >> return cxl_p1_read(adapter, CXL_PSL_Timebase); >> @@ -514,6 +638,11 @@ static void cxl_setup_psl_timebase(struct cxl >> *adapter, struct pci_dev *dev) >> return; >> } >> >> +static int init_implementation_afu_regs_psl9(struct cxl_afu *afu) >> +{ >> + return 0; >> +} >> + >> static int init_implementation_afu_regs_psl8(struct cxl_afu *afu) >> { >> /* read/write masks for this slice */ >> @@ -612,7 +741,7 @@ static int setup_cxl_bars(struct pci_dev *dev) >> /* >> * BAR 4/5 has a special meaning for CXL and must be programmed >> with a >> * special value corresponding to the CXL protocol address range. >> - * For POWER 8 that means bits 48:49 must be set to 10 >> + * For POWER 8/9 that means bits 48:49 must be set to 10 >> */ >> pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000); >> pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000); >> @@ -997,6 +1126,52 @@ static int cxl_afu_descriptor_looks_ok(struct >> cxl_afu *afu) >> return 0; >> } >> >> +static int sanitise_afu_regs_psl9(struct cxl_afu *afu) >> +{ >> + u64 reg; >> + >> + /* >> + * Clear out any regs that contain either an IVTE or address or >> may be >> + * waiting on an acknowledgment to try to be a bit safer as we >> bring >> + * it online >> + */ >> + reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); >> + if ((reg & CXL_AFU_Cntl_An_ES_MASK) != >> CXL_AFU_Cntl_An_ES_Disabled) { >> + dev_warn(&afu->dev, "WARNING: AFU was not disabled: >> %#016llx\n", reg); >> + if (cxl_ops->afu_reset(afu)) >> + return -EIO; >> + if (cxl_afu_disable(afu)) >> + return -EIO; >> + if (cxl_psl_purge(afu)) >> + return -EIO; >> + } >> + cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000); >> + cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000); >> + reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An); >> + if (reg) { >> + dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg); >> + if (reg & CXL_PSL9_DSISR_An_TF) >> + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); >> + else >> + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); >> + } >> + if (afu->adapter->native->sl_ops->register_serr_irq) { >> + reg = cxl_p1n_read(afu, CXL_PSL_SERR_An); >> + if (reg) { >> + if (reg & ~0x000000007fffffff) >> + dev_warn(&afu->dev, "AFU had pending SERR: >> %#016llx\n", reg); >> + cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff); >> + } >> + } >> + reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); >> + if (reg) { >> + dev_warn(&afu->dev, "AFU had pending error status: >> %#016llx\n", reg); >> + cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg); >> + } >> + >> + return 0; >> +} >> + >> static int sanitise_afu_regs_psl8(struct cxl_afu *afu) >> { >> u64 reg; >> @@ -1254,10 +1429,10 @@ int cxl_pci_reset(struct cxl *adapter) >> >> /* >> * The adapter is about to be reset, so ignore errors. >> - * Not supported on P9 DD1 but don't forget to enable it >> - * on P9 DD2 >> + * Not supported on P9 DD1 >> */ >> - if (cxl_is_power8()) >> + if ((cxl_is_power8()) || >> + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) >> cxl_data_cache_flush(adapter); >> >> /* pcie_warm_reset requests a fundamental pci reset which >> includes a >> @@ -1393,6 +1568,9 @@ static bool cxl_compatible_caia_version(struct >> cxl *adapter) >> if (cxl_is_power8() && (adapter->caia_major == 1)) >> return true; >> >> + if (cxl_is_power9() && (adapter->caia_major == 2)) >> + return true; >> + >> return false; >> } >> >> @@ -1460,8 +1638,12 @@ static int sanitise_adapter_regs(struct cxl >> *adapter) >> /* Clear PSL tberror bit by writing 1 to it */ >> cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror); >> >> - if (adapter->native->sl_ops->invalidate_all) >> + if (adapter->native->sl_ops->invalidate_all) { >> + /* do not invalidate ERAT entries when not reloading on >> PERST */ >> + if (cxl_is_power9() && (adapter->perst_loads_image)) >> + return 0; >> rc = adapter->native->sl_ops->invalidate_all(adapter); >> + } >> >> return rc; >> } >> @@ -1546,6 +1728,30 @@ static void cxl_deconfigure_adapter(struct cxl >> *adapter) >> pci_disable_device(pdev); >> } >> >> +static const struct cxl_service_layer_ops psl9_ops = { >> + .adapter_regs_init = init_implementation_adapter_regs_psl9, >> + .invalidate_all = cxl_invalidate_all_psl9, >> + .afu_regs_init = init_implementation_afu_regs_psl9, >> + .sanitise_afu_regs = sanitise_afu_regs_psl9, >> + .register_serr_irq = cxl_native_register_serr_irq, >> + .release_serr_irq = cxl_native_release_serr_irq, >> + .handle_interrupt = cxl_irq_psl9, >> + .fail_irq = cxl_fail_irq_psl, >> + .activate_dedicated_process = cxl_activate_dedicated_process_psl9, >> + .attach_afu_directed = cxl_attach_afu_directed_psl9, >> + .attach_dedicated_process = cxl_attach_dedicated_process_psl9, >> + .update_dedicated_ivtes = cxl_update_dedicated_ivtes_psl9, >> + .debugfs_add_adapter_regs = cxl_debugfs_add_adapter_regs_psl9, >> + .debugfs_add_afu_regs = cxl_debugfs_add_afu_regs_psl9, >> + .psl_irq_dump_registers = cxl_native_irq_dump_regs_psl9, >> + .err_irq_dump_registers = cxl_native_err_irq_dump_regs, >> + .debugfs_stop_trace = cxl_stop_trace_psl9, >> + .write_timebase_ctrl = write_timebase_ctrl_psl9, >> + .timebase_read = timebase_read_psl9, >> + .capi_mode = OPAL_PHB_CAPI_MODE_CAPI, >> + .needs_reset_before_disable = true, >> +}; >> + >> static const struct cxl_service_layer_ops psl8_ops = { >> .adapter_regs_init = init_implementation_adapter_regs_psl8, >> .invalidate_all = cxl_invalidate_all_psl8, >> @@ -1589,6 +1795,9 @@ static void set_sl_ops(struct cxl *adapter, >> struct pci_dev *dev) >> if (cxl_is_power8()) { >> dev_info(&dev->dev, "Device uses a PSL8\n"); >> adapter->native->sl_ops = &psl8_ops; >> + } else { >> + dev_info(&dev->dev, "Device uses a PSL9\n"); >> + adapter->native->sl_ops = &psl9_ops; >> } >> } >> } >> @@ -1659,8 +1868,12 @@ static void cxl_pci_remove_adapter(struct cxl >> *adapter) >> cxl_sysfs_adapter_remove(adapter); >> cxl_debugfs_adapter_remove(adapter); >> >> - /* Flush adapter datacache as its about to be removed */ >> - cxl_data_cache_flush(adapter); >> + /* Flush adapter datacache as its about to be removed. >> + * Not supported on P9 DD1 >> + */ >> + if ((cxl_is_power8()) || >> + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) >> + cxl_data_cache_flush(adapter); >> >> cxl_deconfigure_adapter(adapter); >> >> @@ -1744,6 +1957,11 @@ static int cxl_probe(struct pci_dev *dev, >> const struct pci_device_id *id) >> return -ENODEV; >> } >> >> + if (cxl_is_power9() && !radix_enabled()) { >> + dev_info(&dev->dev, "Only Radix mode supported\n"); >> + return -ENODEV; >> + } >> + >> if (cxl_verbose) >> dump_cxl_config_space(dev); >> >> diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h >> index 751d611..b8e300a 100644 >> --- a/drivers/misc/cxl/trace.h >> +++ b/drivers/misc/cxl/trace.h >> @@ -17,6 +17,15 @@ >> >> #include "cxl.h" >> >> +#define dsisr_psl9_flags(flags) \ >> + __print_flags(flags, "|", \ >> + { CXL_PSL9_DSISR_An_CO_MASK, "FR" }, \ >> + { CXL_PSL9_DSISR_An_TF, "TF" }, \ >> + { CXL_PSL9_DSISR_An_PE, "PE" }, \ >> + { CXL_PSL9_DSISR_An_AE, "AE" }, \ >> + { CXL_PSL9_DSISR_An_OC, "OC" }, \ >> + { CXL_PSL9_DSISR_An_S, "S" }) >> + >> #define DSISR_FLAGS \ >> { CXL_PSL_DSISR_An_DS, "DS" }, \ >> { CXL_PSL_DSISR_An_DM, "DM" }, \ >> @@ -154,6 +163,40 @@ TRACE_EVENT(cxl_afu_irq, >> ) >> ); >> >> +TRACE_EVENT(cxl_psl9_irq, >> + TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), >> + >> + TP_ARGS(ctx, irq, dsisr, dar), >> + >> + TP_STRUCT__entry( >> + __field(u8, card) >> + __field(u8, afu) >> + __field(u16, pe) >> + __field(int, irq) >> + __field(u64, dsisr) >> + __field(u64, dar) >> + ), >> + >> + TP_fast_assign( >> + __entry->card = ctx->afu->adapter->adapter_num; >> + __entry->afu = ctx->afu->slice; >> + __entry->pe = ctx->pe; >> + __entry->irq = irq; >> + __entry->dsisr = dsisr; >> + __entry->dar = dar; >> + ), >> + >> + TP_printk("afu%i.%i pe=%i irq=%i dsisr=0x%016llx dsisr=%s >> dar=0x%016llx", >> + __entry->card, >> + __entry->afu, >> + __entry->pe, >> + __entry->irq, >> + __entry->dsisr, >> + dsisr_psl9_flags(__entry->dsisr), >> + __entry->dar >> + ) >> +); >> + >> TRACE_EVENT(cxl_psl_irq, >> TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), >>
diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index ac2531e..45363be 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -188,12 +188,24 @@ int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma) if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { if (start + len > ctx->afu->adapter->ps_size) return -EINVAL; + + if (cxl_is_psl9(ctx->afu)) { + /* make sure there is a valid problem state + * area space for this AFU + */ + if (ctx->master && !ctx->afu->psa) { + pr_devel("AFU doesn't support mmio space\n"); + return -EINVAL; + } + + /* Can't mmap until the AFU is enabled */ + if (!ctx->afu->enabled) + return -EBUSY; + } } else { if (start + len > ctx->psn_size) return -EINVAL; - } - if (ctx->afu->current_mode != CXL_MODE_DEDICATED) { /* make sure there is a valid per process space for this AFU */ if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) { pr_devel("AFU doesn't support mmio space\n"); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index 2f2d9e4..aac0504 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -63,7 +63,7 @@ typedef struct { /* Memory maps. Ref CXL Appendix A */ /* PSL Privilege 1 Memory Map */ -/* Configuration and Control area */ +/* Configuration and Control area - CAIA 1&2 */ static const cxl_p1_reg_t CXL_PSL_CtxTime = {0x0000}; static const cxl_p1_reg_t CXL_PSL_ErrIVTE = {0x0008}; static const cxl_p1_reg_t CXL_PSL_KEY1 = {0x0010}; @@ -98,11 +98,29 @@ static const cxl_p1_reg_t CXL_XSL_Timebase = {0x0100}; static const cxl_p1_reg_t CXL_XSL_TB_CTLSTAT = {0x0108}; static const cxl_p1_reg_t CXL_XSL_FEC = {0x0158}; static const cxl_p1_reg_t CXL_XSL_DSNCTL = {0x0168}; +/* PSL registers - CAIA 2 */ +static const cxl_p1_reg_t CXL_PSL9_CONTROL = {0x0020}; +static const cxl_p1_reg_t CXL_XSL9_DSNCTL = {0x0168}; +static const cxl_p1_reg_t CXL_PSL9_FIR1 = {0x0300}; +static const cxl_p1_reg_t CXL_PSL9_FIR2 = {0x0308}; +static const cxl_p1_reg_t CXL_PSL9_Timebase = {0x0310}; +static const cxl_p1_reg_t CXL_PSL9_DEBUG = {0x0320}; +static const cxl_p1_reg_t CXL_PSL9_FIR_CNTL = {0x0348}; +static const cxl_p1_reg_t CXL_PSL9_DSNDCTL = {0x0350}; +static const cxl_p1_reg_t CXL_PSL9_TB_CTLSTAT = {0x0340}; +static const cxl_p1_reg_t CXL_PSL9_TRACECFG = {0x0368}; +static const cxl_p1_reg_t CXL_PSL9_APCDEDALLOC = {0x0378}; +static const cxl_p1_reg_t CXL_PSL9_APCDEDTYPE = {0x0380}; +static const cxl_p1_reg_t CXL_PSL9_TNR_ADDR = {0x0388}; +static const cxl_p1_reg_t CXL_PSL9_GP_CT = {0x0398}; +static const cxl_p1_reg_t CXL_XSL9_IERAT = {0x0588}; +static const cxl_p1_reg_t CXL_XSL9_ILPP = {0x0590}; + /* 0x7F00:7FFF Reserved PCIe MSI-X Pending Bit Array area */ /* 0x8000:FFFF Reserved PCIe MSI-X Table Area */ /* PSL Slice Privilege 1 Memory Map */ -/* Configuration Area */ +/* Configuration Area - CAIA 1&2 */ static const cxl_p1n_reg_t CXL_PSL_SR_An = {0x00}; static const cxl_p1n_reg_t CXL_PSL_LPID_An = {0x08}; static const cxl_p1n_reg_t CXL_PSL_AMBAR_An = {0x10}; @@ -111,17 +129,18 @@ static const cxl_p1n_reg_t CXL_PSL_ID_An = {0x20}; static const cxl_p1n_reg_t CXL_PSL_SERR_An = {0x28}; /* Memory Management and Lookaside Buffer Management - CAIA 1*/ static const cxl_p1n_reg_t CXL_PSL_SDR_An = {0x30}; +/* Memory Management and Lookaside Buffer Management - CAIA 1&2 */ static const cxl_p1n_reg_t CXL_PSL_AMOR_An = {0x38}; -/* Pointer Area */ +/* Pointer Area - CAIA 1&2 */ static const cxl_p1n_reg_t CXL_HAURP_An = {0x80}; static const cxl_p1n_reg_t CXL_PSL_SPAP_An = {0x88}; static const cxl_p1n_reg_t CXL_PSL_LLCMD_An = {0x90}; -/* Control Area */ +/* Control Area - CAIA 1&2 */ static const cxl_p1n_reg_t CXL_PSL_SCNTL_An = {0xA0}; static const cxl_p1n_reg_t CXL_PSL_CtxTime_An = {0xA8}; static const cxl_p1n_reg_t CXL_PSL_IVTE_Offset_An = {0xB0}; static const cxl_p1n_reg_t CXL_PSL_IVTE_Limit_An = {0xB8}; -/* 0xC0:FF Implementation Dependent Area */ +/* 0xC0:FF Implementation Dependent Area - CAIA 1&2 */ static const cxl_p1n_reg_t CXL_PSL_FIR_SLICE_An = {0xC0}; static const cxl_p1n_reg_t CXL_AFU_DEBUG_An = {0xC8}; /* 0xC0:FF Implementation Dependent Area - CAIA 1 */ @@ -131,7 +150,7 @@ static const cxl_p1n_reg_t CXL_PSL_RXCTL_A = {0xE0}; static const cxl_p1n_reg_t CXL_PSL_SLICE_TRACE = {0xE8}; /* PSL Slice Privilege 2 Memory Map */ -/* Configuration and Control Area */ +/* Configuration and Control Area - CAIA 1&2 */ static const cxl_p2n_reg_t CXL_PSL_PID_TID_An = {0x000}; static const cxl_p2n_reg_t CXL_CSRP_An = {0x008}; /* Configuration and Control Area - CAIA 1 */ @@ -145,17 +164,17 @@ static const cxl_p2n_reg_t CXL_PSL_AMR_An = {0x030}; static const cxl_p2n_reg_t CXL_SLBIE_An = {0x040}; static const cxl_p2n_reg_t CXL_SLBIA_An = {0x048}; static const cxl_p2n_reg_t CXL_SLBI_Select_An = {0x050}; -/* Interrupt Registers */ +/* Interrupt Registers - CAIA 1&2 */ static const cxl_p2n_reg_t CXL_PSL_DSISR_An = {0x060}; static const cxl_p2n_reg_t CXL_PSL_DAR_An = {0x068}; static const cxl_p2n_reg_t CXL_PSL_DSR_An = {0x070}; static const cxl_p2n_reg_t CXL_PSL_TFC_An = {0x078}; static const cxl_p2n_reg_t CXL_PSL_PEHandle_An = {0x080}; static const cxl_p2n_reg_t CXL_PSL_ErrStat_An = {0x088}; -/* AFU Registers */ +/* AFU Registers - CAIA 1&2 */ static const cxl_p2n_reg_t CXL_AFU_Cntl_An = {0x090}; static const cxl_p2n_reg_t CXL_AFU_ERR_An = {0x098}; -/* Work Element Descriptor */ +/* Work Element Descriptor - CAIA 1&2 */ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; /* 0x0C0:FFF Implementation Dependent Area */ @@ -182,6 +201,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PSL_SR_An_SF MSR_SF /* 64bit */ #define CXL_PSL_SR_An_TA (1ull << (63-1)) /* Tags active, GA1: 0 */ #define CXL_PSL_SR_An_HV MSR_HV /* Hypervisor, GA1: 0 */ +#define CXL_PSL_SR_An_XLAT_hpt (0ull << (63-6))/* Hashed page table (HPT) mode */ +#define CXL_PSL_SR_An_XLAT_roh (2ull << (63-6))/* Radix on HPT mode */ +#define CXL_PSL_SR_An_XLAT_ror (3ull << (63-6))/* Radix on Radix mode */ +#define CXL_PSL_SR_An_BOT (1ull << (63-10)) /* Use the in-memory segment table */ #define CXL_PSL_SR_An_PR MSR_PR /* Problem state, GA1: 1 */ #define CXL_PSL_SR_An_ISL (1ull << (63-53)) /* Ignore Segment Large Page */ #define CXL_PSL_SR_An_TC (1ull << (63-54)) /* Page Table secondary hash */ @@ -298,12 +321,38 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PSL_DSISR_An_S DSISR_ISSTORE /* Access was afu_wr or afu_zero */ #define CXL_PSL_DSISR_An_K DSISR_KEYFAULT /* Access not permitted by virtual page class key protection */ +/****** CXL_PSL_DSISR_An - CAIA 2 ****************************************************/ +#define CXL_PSL9_DSISR_An_TF (1ull << (63-3)) /* Translation fault */ +#define CXL_PSL9_DSISR_An_PE (1ull << (63-4)) /* PSL Error (implementation specific) */ +#define CXL_PSL9_DSISR_An_AE (1ull << (63-5)) /* AFU Error */ +#define CXL_PSL9_DSISR_An_OC (1ull << (63-6)) /* OS Context Warning */ +#define CXL_PSL9_DSISR_An_S (1ull << (63-38)) /* TF for a write operation */ +#define CXL_PSL9_DSISR_PENDING (CXL_PSL9_DSISR_An_TF | CXL_PSL9_DSISR_An_PE | CXL_PSL9_DSISR_An_AE | CXL_PSL9_DSISR_An_OC) +/* NOTE: Bits 56:63 (Checkout Response Status) are valid when DSISR_An[TF] = 1 + * Status (0:7) Encoding + */ +#define CXL_PSL9_DSISR_An_CO_MASK 0x00000000000000ffULL +#define CXL_PSL9_DSISR_An_SF 0x0000000000000080ULL /* Segment Fault 0b10000000 */ +#define CXL_PSL9_DSISR_An_PF_SLR 0x0000000000000088ULL /* PTE not found (Single Level Radix) 0b10001000 */ +#define CXL_PSL9_DSISR_An_PF_RGC 0x000000000000008CULL /* PTE not found (Radix Guest (child)) 0b10001100 */ +#define CXL_PSL9_DSISR_An_PF_RGP 0x0000000000000090ULL /* PTE not found (Radix Guest (parent)) 0b10010000 */ +#define CXL_PSL9_DSISR_An_PF_HRH 0x0000000000000094ULL /* PTE not found (HPT/Radix Host) 0b10010100 */ +#define CXL_PSL9_DSISR_An_PF_STEG 0x000000000000009CULL /* PTE not found (STEG VA) 0b10011100 */ + /****** CXL_PSL_TFC_An ******************************************************/ #define CXL_PSL_TFC_An_A (1ull << (63-28)) /* Acknowledge non-translation fault */ #define CXL_PSL_TFC_An_C (1ull << (63-29)) /* Continue (abort transaction) */ #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */ #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL transaction */ +/****** CXL_XSL9_IERAT_ERAT - CAIA 2 **********************************/ +#define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */ +#define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */ +#define CXL_XSL9_IERAT_PRS (1ull << (63-4)) /* PRS bit for Radix invalidations */ +#define CXL_XSL9_IERAT_INVR (1ull << (63-3)) /* Invalidate Radix */ +#define CXL_XSL9_IERAT_IALL (1ull << (63-8)) /* Invalidate All */ +#define CXL_XSL9_IERAT_IINPROG (1ull << (63-63)) /* Invalidate in progress */ + /* cxl_process_element->software_status */ #define CXL_PE_SOFTWARE_STATE_V (1ul << (31 - 0)) /* Valid */ #define CXL_PE_SOFTWARE_STATE_C (1ul << (31 - 29)) /* Complete */ @@ -654,25 +703,38 @@ int cxl_pci_reset(struct cxl *adapter); void cxl_pci_release_afu(struct device *dev); ssize_t cxl_pci_read_adapter_vpd(struct cxl *adapter, void *buf, size_t len); -/* common == phyp + powernv */ +/* common == phyp + powernv - CAIA 1&2 */ struct cxl_process_element_common { __be32 tid; __be32 pid; __be64 csrp; - __be64 aurp0; - __be64 aurp1; - __be64 sstp0; - __be64 sstp1; + union { + struct { + __be64 aurp0; + __be64 aurp1; + __be64 sstp0; + __be64 sstp1; + } psl8; /* CAIA 1 */ + struct { + u8 reserved2[8]; + u8 reserved3[8]; + u8 reserved4[8]; + u8 reserved5[8]; + } psl9; /* CAIA 2 */ + } u; __be64 amr; - u8 reserved3[4]; + u8 reserved6[4]; __be64 wed; } __packed; -/* just powernv */ +/* just powernv - CAIA 1&2 */ struct cxl_process_element { __be64 sr; __be64 SPOffset; - __be64 sdr; + union { + __be64 sdr; /* CAIA 1 */ + u8 reserved1[8]; /* CAIA 2 */ + } u; __be64 haurp; __be32 ctxtime; __be16 ivte_offsets[4]; @@ -761,6 +823,16 @@ static inline bool cxl_is_power8(void) return false; } +static inline bool cxl_is_power9(void) +{ + /* intermediate solution */ + if (!cxl_is_power8() && + (cpu_has_feature(CPU_FTRS_POWER9) || + cpu_has_feature(CPU_FTR_POWER9_DD1))) + return true; + return false; +} + static inline bool cxl_is_psl8(struct cxl_afu *afu) { if (afu->adapter->caia_major == 1) @@ -768,6 +840,13 @@ static inline bool cxl_is_psl8(struct cxl_afu *afu) return false; } +static inline bool cxl_is_psl9(struct cxl_afu *afu) +{ + if (afu->adapter->caia_major == 2) + return true; + return false; +} + ssize_t cxl_pci_afu_read_err_buffer(struct cxl_afu *afu, char *buf, loff_t off, size_t count); @@ -794,7 +873,6 @@ int cxl_update_properties(struct device_node *dn, struct property *new_prop); void cxl_remove_adapter_nr(struct cxl *adapter); -int cxl_alloc_spa(struct cxl_afu *afu); void cxl_release_spa(struct cxl_afu *afu); dev_t cxl_get_dev(void); @@ -832,9 +910,13 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count); void afu_release_irqs(struct cxl_context *ctx, void *cookie); void afu_irq_name_free(struct cxl_context *ctx); +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, u64 amr); int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr); +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu); int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu); +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 wed, u64 amr); int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 wed, u64 amr); +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx); void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx); #ifdef CONFIG_DEBUG_FS @@ -845,9 +927,12 @@ int cxl_debugfs_adapter_add(struct cxl *adapter); void cxl_debugfs_adapter_remove(struct cxl *adapter); int cxl_debugfs_afu_add(struct cxl_afu *afu); void cxl_debugfs_afu_remove(struct cxl_afu *afu); +void cxl_stop_trace_psl9(struct cxl *cxl); void cxl_stop_trace_psl8(struct cxl *cxl); +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir); void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, struct dentry *dir); +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir); void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir); #else /* CONFIG_DEBUG_FS */ @@ -879,10 +964,19 @@ static inline void cxl_debugfs_afu_remove(struct cxl_afu *afu) { } +static inline void cxl_stop_trace_psl9(struct cxl *cxl) +{ +} + static inline void cxl_stop_trace_psl8(struct cxl *cxl) { } +static inline void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, + struct dentry *dir) +{ +} + static inline void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) { @@ -893,6 +987,10 @@ static inline void cxl_debugfs_add_adapter_regs_xsl(struct cxl *adapter, { } +static inline void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir) +{ +} + static inline void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) { } @@ -951,7 +1049,9 @@ struct cxl_irq_info { }; void cxl_assign_psn_space(struct cxl_context *ctx); +int cxl_invalidate_all_psl9(struct cxl *adapter); int cxl_invalidate_all_psl8(struct cxl *adapter); +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info); irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info); irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct cxl_irq_info *irq_info); int cxl_register_one_irq(struct cxl *adapter, irq_handler_t handler, @@ -964,6 +1064,7 @@ int cxl_data_cache_flush(struct cxl *adapter); int cxl_afu_disable(struct cxl_afu *afu); int cxl_psl_purge(struct cxl_afu *afu); +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx); void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx); void cxl_native_err_irq_dump_regs(struct cxl *adapter); int cxl_pci_vphb_add(struct cxl_afu *afu); diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index 43a1a27..eae9d74 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -15,6 +15,12 @@ static struct dentry *cxl_debugfs; +void cxl_stop_trace_psl9(struct cxl *adapter) +{ + /* Stop the trace */ + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x4480000000000000ULL); +} + void cxl_stop_trace_psl8(struct cxl *adapter) { int slice; @@ -53,6 +59,14 @@ static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, (void __force *)value, &fops_io_x64); } +void cxl_debugfs_add_adapter_regs_psl9(struct cxl *adapter, struct dentry *dir) +{ + debugfs_create_io_x64("fir1", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR1)); + debugfs_create_io_x64("fir2", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR2)); + debugfs_create_io_x64("fir_cntl", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_FIR_CNTL)); + debugfs_create_io_x64("trace", S_IRUSR | S_IWUSR, dir, _cxl_p1_addr(adapter, CXL_PSL9_TRACECFG)); +} + void cxl_debugfs_add_adapter_regs_psl8(struct cxl *adapter, struct dentry *dir) { debugfs_create_io_x64("fir1", S_IRUSR, dir, _cxl_p1_addr(adapter, CXL_PSL_FIR1)); @@ -92,6 +106,11 @@ void cxl_debugfs_adapter_remove(struct cxl *adapter) debugfs_remove_recursive(adapter->debugfs); } +void cxl_debugfs_add_afu_regs_psl9(struct cxl_afu *afu, struct dentry *dir) +{ + debugfs_create_io_x64("serr", S_IRUSR, dir, _cxl_p1n_addr(afu, CXL_PSL_SERR_An)); +} + void cxl_debugfs_add_afu_regs_psl8(struct cxl_afu *afu, struct dentry *dir) { debugfs_create_io_x64("sstp0", S_IRUSR, dir, _cxl_p2n_addr(afu, CXL_SSTP0_An)); diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c index f24c15c..381ae70 100644 --- a/drivers/misc/cxl/fault.c +++ b/drivers/misc/cxl/fault.c @@ -146,25 +146,26 @@ static void cxl_handle_page_fault(struct cxl_context *ctx, return cxl_ack_ae(ctx); } - /* - * update_mmu_cache() will not have loaded the hash since current->trap - * is not a 0x400 or 0x300, so just call hash_page_mm() here. - */ - access = _PAGE_PRESENT | _PAGE_READ; - if (dsisr & CXL_PSL_DSISR_An_S) - access |= _PAGE_WRITE; - - access |= _PAGE_PRIVILEGED; - if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) - access &= ~_PAGE_PRIVILEGED; - - if (dsisr & DSISR_NOHPTE) - inv_flags |= HPTE_NOHPTE_UPDATE; - - local_irq_save(flags); - hash_page_mm(mm, dar, access, 0x300, inv_flags); - local_irq_restore(flags); - + if (!radix_enabled()) { + /* + * update_mmu_cache() will not have loaded the hash since current->trap + * is not a 0x400 or 0x300, so just call hash_page_mm() here. + */ + access = _PAGE_PRESENT | _PAGE_READ; + if (dsisr & CXL_PSL_DSISR_An_S) + access |= _PAGE_WRITE; + + access |= _PAGE_PRIVILEGED; + if ((!ctx->kernel) || (REGION_ID(dar) == USER_REGION_ID)) + access &= ~_PAGE_PRIVILEGED; + + if (dsisr & DSISR_NOHPTE) + inv_flags |= HPTE_NOHPTE_UPDATE; + + local_irq_save(flags); + hash_page_mm(mm, dar, access, 0x300, inv_flags); + local_irq_restore(flags); + } pr_devel("Page fault successfully handled for pe: %i!\n", ctx->pe); cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_R, 0); } @@ -179,12 +180,33 @@ static struct mm_struct *get_mem_context(struct cxl_context *ctx) return NULL; if (!atomic_inc_not_zero(&ctx->mm->mm_users)) - return ctx->mm; + return NULL; - return NULL; + return ctx->mm; } +static bool cxl_is_segment_miss(struct cxl_context *ctx, u64 dsisr) +{ + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DS)) + return true; + return false; +} + +static bool cxl_is_page_fault(struct cxl_context *ctx, u64 dsisr) +{ + if ((cxl_is_psl8(ctx->afu)) && (dsisr & CXL_PSL_DSISR_An_DM)) + return true; + + if ((cxl_is_psl9(ctx->afu)) && + ((dsisr & CXL_PSL9_DSISR_An_CO_MASK) & + (CXL_PSL9_DSISR_An_PF_SLR | CXL_PSL9_DSISR_An_PF_RGC | + CXL_PSL9_DSISR_An_PF_RGP | CXL_PSL9_DSISR_An_PF_HRH | + CXL_PSL9_DSISR_An_PF_STEG))) + return true; + + return false; +} void cxl_handle_fault(struct work_struct *fault_work) { @@ -230,14 +252,12 @@ void cxl_handle_fault(struct work_struct *fault_work) } } - if (cxl_is_psl8(ctx->afu)) { - if (dsisr & CXL_PSL_DSISR_An_DS) - cxl_handle_segment_miss(ctx, mm, dar); - else if (dsisr & CXL_PSL_DSISR_An_DM) - cxl_handle_page_fault(ctx, mm, dsisr, dar); - else - WARN(1, "cxl_handle_fault has nothing to handle\n"); - } + if (cxl_is_segment_miss(ctx, dsisr)) + cxl_handle_segment_miss(ctx, mm, dar); + else if (cxl_is_page_fault(ctx, dsisr)) + cxl_handle_page_fault(ctx, mm, dsisr, dar); + else + WARN(1, "cxl_handle_fault has nothing to handle\n"); if (mm) mmput(mm); diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 3ad7381..f58b4b6c 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -551,13 +551,13 @@ static int attach_afu_directed(struct cxl_context *ctx, u64 wed, u64 amr) elem->common.tid = cpu_to_be32(0); /* Unused */ elem->common.pid = cpu_to_be32(pid); elem->common.csrp = cpu_to_be64(0); /* disable */ - elem->common.aurp0 = cpu_to_be64(0); /* disable */ - elem->common.aurp1 = cpu_to_be64(0); /* disable */ + elem->common.u.psl8.aurp0 = cpu_to_be64(0); /* disable */ + elem->common.u.psl8.aurp1 = cpu_to_be64(0); /* disable */ cxl_prefault(ctx, wed); - elem->common.sstp0 = cpu_to_be64(ctx->sstp0); - elem->common.sstp1 = cpu_to_be64(ctx->sstp1); + elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); + elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); /* * Ensure we have at least one interrupt allocated to take faults for diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index fa9f8a2..1eb5168 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -34,6 +34,59 @@ static irqreturn_t schedule_cxl_fault(struct cxl_context *ctx, u64 dsisr, u64 da return IRQ_HANDLED; } +irqreturn_t cxl_irq_psl9(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info) +{ + u64 dsisr, dar; + + dsisr = irq_info->dsisr; + dar = irq_info->dar; + + trace_cxl_psl9_irq(ctx, irq, dsisr, dar); + + pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar); + + if (dsisr & CXL_PSL9_DSISR_An_TF) { + pr_devel("CXL interrupt: Scheduling translation fault" + " handling for later (pe: %i)\n", ctx->pe); + return schedule_cxl_fault(ctx, dsisr, dar); + } + + if (dsisr & CXL_PSL9_DSISR_An_PE) + return cxl_ops->handle_psl_slice_error(ctx, dsisr, + irq_info->errstat); + if (dsisr & CXL_PSL9_DSISR_An_AE) { + pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err); + + if (ctx->pending_afu_err) { + /* + * This shouldn't happen - the PSL treats these errors + * as fatal and will have reset the AFU, so there's not + * much point buffering multiple AFU errors. + * OTOH if we DO ever see a storm of these come in it's + * probably best that we log them somewhere: + */ + dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " + "undelivered to pe %i: 0x%016llx\n", + ctx->pe, irq_info->afu_err); + } else { + spin_lock(&ctx->lock); + ctx->afu_err = irq_info->afu_err; + ctx->pending_afu_err = 1; + spin_unlock(&ctx->lock); + + wake_up_all(&ctx->wq); + } + + cxl_ops->ack_irq(ctx, CXL_PSL_TFC_An_A, 0); + return IRQ_HANDLED; + } + if (dsisr & CXL_PSL9_DSISR_An_OC) + pr_devel("CXL interrupt: OS Context Warning\n"); + + WARN(1, "Unhandled CXL PSL IRQ\n"); + return IRQ_HANDLED; +} + irqreturn_t cxl_irq_psl8(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_info) { u64 dsisr, dar; diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 7b86ffa..67c9bc6 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -120,6 +120,7 @@ int cxl_psl_purge(struct cxl_afu *afu) u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); u64 dsisr, dar; u64 start, end; + u64 trans_fault = 0x0ULL; unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); int rc = 0; @@ -127,6 +128,11 @@ int cxl_psl_purge(struct cxl_afu *afu) pr_devel("PSL purge request\n"); + if (cxl_is_psl8(afu)) + trans_fault = CXL_PSL_DSISR_TRANS; + if (cxl_is_psl9(afu)) + trans_fault = CXL_PSL9_DSISR_An_TF; + if (!cxl_ops->link_ok(afu->adapter, afu)) { dev_warn(&afu->dev, "PSL Purge called with link down, ignoring\n"); rc = -EIO; @@ -158,22 +164,21 @@ int cxl_psl_purge(struct cxl_afu *afu) pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx" " PSL_DSISR: 0x%016llx\n", PSL_CNTL, dsisr); - if (cxl_is_psl8(afu)) { - if (dsisr & CXL_PSL_DSISR_TRANS) { - dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); - dev_notice(&afu->dev, "PSL purge terminating " - "pending translation, " - "DSISR: 0x%016llx, DAR: 0x%016llx\n", - dsisr, dar); - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); - } else if (dsisr) { - dev_notice(&afu->dev, "PSL purge acknowledging " - "pending non-translation fault, " - "DSISR: 0x%016llx\n", dsisr); - cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); - } else { - cpu_relax(); - } + + if (dsisr & trans_fault) { + dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); + dev_notice(&afu->dev, "PSL purge terminating " + "pending translation, " + "DSISR: 0x%016llx, DAR: 0x%016llx\n", + dsisr, dar); + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); + } else if (dsisr) { + dev_notice(&afu->dev, "PSL purge acknowledging " + "pending non-translation fault, " + "DSISR: 0x%016llx\n", dsisr); + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); + } else { + cpu_relax(); } PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An); } @@ -205,7 +210,7 @@ static int spa_max_procs(int spa_size) return ((spa_size / 8) - 96) / 17; } -int cxl_alloc_spa(struct cxl_afu *afu) +static int cxl_alloc_spa(struct cxl_afu *afu, int mode) { unsigned spa_size; @@ -218,7 +223,8 @@ int cxl_alloc_spa(struct cxl_afu *afu) if (spa_size > 0x100000) { dev_warn(&afu->dev, "num_of_processes too large for the SPA, limiting to %i (0x%x)\n", afu->native->spa_max_procs, afu->native->spa_size); - afu->num_procs = afu->native->spa_max_procs; + if (mode != CXL_MODE_DEDICATED) + afu->num_procs = afu->native->spa_max_procs; break; } @@ -267,6 +273,35 @@ void cxl_release_spa(struct cxl_afu *afu) } } +/* Invalidation of all ERAT entries is no longer required by CAIA2. Use + * only for debug + */ +int cxl_invalidate_all_psl9(struct cxl *adapter) +{ + unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); + u64 ierat; + + pr_devel("CXL adapter - invalidation of all ERAT entries\n"); + + /* Invalidates all ERAT entries for Radix or HPT */ + ierat = CXL_XSL9_IERAT_IALL; + if (radix_enabled()) + ierat |= CXL_XSL9_IERAT_INVR; + cxl_p1_write(adapter, CXL_XSL9_IERAT, ierat); + + while (cxl_p1_read(adapter, CXL_XSL9_IERAT) & CXL_XSL9_IERAT_IINPROG) { + if (time_after_eq(jiffies, timeout)) { + dev_warn(&adapter->dev, + "WARNING: CXL adapter invalidation of all ERAT entries timed out!\n"); + return -EBUSY; + } + if (!cxl_ops->link_ok(adapter, NULL)) + return -EIO; + cpu_relax(); + } + return 0; +} + int cxl_invalidate_all_psl8(struct cxl *adapter) { unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); @@ -503,7 +538,7 @@ static int activate_afu_directed(struct cxl_afu *afu) afu->num_procs = afu->max_procs_virtualised; if (afu->native->spa == NULL) { - if (cxl_alloc_spa(afu)) + if (cxl_alloc_spa(afu, CXL_MODE_DIRECTED)) return -ENOMEM; } attach_spa(afu); @@ -553,10 +588,19 @@ static u64 calculate_sr(struct cxl_context *ctx) sr |= (mfmsr() & MSR_SF) | CXL_PSL_SR_An_HV; } else { sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R; - sr &= ~(CXL_PSL_SR_An_HV); + if (radix_enabled()) + sr |= CXL_PSL_SR_An_HV; + else + sr &= ~(CXL_PSL_SR_An_HV); if (!test_tsk_thread_flag(current, TIF_32BIT)) sr |= CXL_PSL_SR_An_SF; } + if (cxl_is_psl9(ctx->afu)) { + if (radix_enabled()) + sr |= CXL_PSL_SR_An_XLAT_ror; + else + sr |= CXL_PSL_SR_An_XLAT_hpt; + } return sr; } @@ -589,6 +633,70 @@ static void update_ivtes_directed(struct cxl_context *ctx) WARN_ON(add_process_element(ctx)); } +static int process_element_entry(struct cxl_context *ctx, u64 wed, u64 amr) +{ + u32 pid; + + cxl_assign_psn_space(ctx); + + ctx->elem->ctxtime = 0; /* disable */ + ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); + ctx->elem->haurp = 0; /* disable */ + + if (ctx->kernel) + pid = 0; + else { + if (ctx->mm == NULL) { + pr_devel("%s: unable to get mm for pe=%d pid=%i\n", + __func__, ctx->pe, pid_nr(ctx->pid)); + return -EINVAL; + } + pid = ctx->mm->context.id; + } + + ctx->elem->common.tid = 0; + ctx->elem->common.pid = cpu_to_be32(pid); + + ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); + + ctx->elem->common.csrp = 0; /* disable */ + + cxl_prefault(ctx, wed); + + /* + * Ensure we have the multiplexed PSL interrupt set up to take faults + * for kernel contexts that may not have allocated any AFU IRQs at all: + */ + if (ctx->irqs.range[0] == 0) { + ctx->irqs.offset[0] = ctx->afu->native->psl_hwirq; + ctx->irqs.range[0] = 1; + } + + ctx->elem->common.amr = cpu_to_be64(amr); + ctx->elem->common.wed = cpu_to_be64(wed); + + return 0; +} + +int cxl_attach_afu_directed_psl9(struct cxl_context *ctx, u64 wed, u64 amr) +{ + int result; + + /* fill the process element entry */ + result = process_element_entry(ctx, wed, amr); + if (result) + return result; + + update_ivtes_directed(ctx); + + /* first guy needs to enable */ + result = cxl_ops->afu_check_and_enable(ctx->afu); + if (result) + return result; + + return add_process_element(ctx); +} + int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) { u32 pid; @@ -599,7 +707,7 @@ int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) ctx->elem->ctxtime = 0; /* disable */ ctx->elem->lpid = cpu_to_be32(mfspr(SPRN_LPID)); ctx->elem->haurp = 0; /* disable */ - ctx->elem->sdr = cpu_to_be64(mfspr(SPRN_SDR1)); + ctx->elem->u.sdr = cpu_to_be64(mfspr(SPRN_SDR1)); pid = current->pid; if (ctx->kernel) @@ -610,13 +718,13 @@ int cxl_attach_afu_directed_psl8(struct cxl_context *ctx, u64 wed, u64 amr) ctx->elem->sr = cpu_to_be64(calculate_sr(ctx)); ctx->elem->common.csrp = 0; /* disable */ - ctx->elem->common.aurp0 = 0; /* disable */ - ctx->elem->common.aurp1 = 0; /* disable */ + ctx->elem->common.u.psl8.aurp0 = 0; /* disable */ + ctx->elem->common.u.psl8.aurp1 = 0; /* disable */ cxl_prefault(ctx, wed); - ctx->elem->common.sstp0 = cpu_to_be64(ctx->sstp0); - ctx->elem->common.sstp1 = cpu_to_be64(ctx->sstp1); + ctx->elem->common.u.psl8.sstp0 = cpu_to_be64(ctx->sstp0); + ctx->elem->common.u.psl8.sstp1 = cpu_to_be64(ctx->sstp1); /* * Ensure we have the multiplexed PSL interrupt set up to take faults @@ -682,6 +790,31 @@ static int deactivate_afu_directed(struct cxl_afu *afu) return 0; } +int cxl_activate_dedicated_process_psl9(struct cxl_afu *afu) +{ + dev_info(&afu->dev, "Activating dedicated process mode\n"); + + /* If XSL is set to dedicated mode (Set in PSL_SCNTL reg), the + * XSL and AFU are programmed to work with a single context. + * The context information should be configured in the SPA area + * index 0 (so PSL_SPAP must be configured before enabling the + * AFU). + */ + afu->num_procs = 1; + if (afu->native->spa == NULL) { + if (cxl_alloc_spa(afu, CXL_MODE_DEDICATED)) + return -ENOMEM; + } + attach_spa(afu); + + cxl_p1n_write(afu, CXL_PSL_SCNTL_An, CXL_PSL_SCNTL_An_PM_Process); + cxl_p1n_write(afu, CXL_PSL_ID_An, CXL_PSL_ID_An_F | CXL_PSL_ID_An_L); + + afu->current_mode = CXL_MODE_DEDICATED; + + return cxl_chardev_d_afu_add(afu); +} + int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu) { dev_info(&afu->dev, "Activating dedicated process mode\n"); @@ -705,6 +838,16 @@ int cxl_activate_dedicated_process_psl8(struct cxl_afu *afu) return cxl_chardev_d_afu_add(afu); } +void cxl_update_dedicated_ivtes_psl9(struct cxl_context *ctx) +{ + int r; + + for (r = 0; r < CXL_IRQ_RANGES; r++) { + ctx->elem->ivte_offsets[r] = cpu_to_be16(ctx->irqs.offset[r]); + ctx->elem->ivte_ranges[r] = cpu_to_be16(ctx->irqs.range[r]); + } +} + void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx) { struct cxl_afu *afu = ctx->afu; @@ -721,6 +864,26 @@ void cxl_update_dedicated_ivtes_psl8(struct cxl_context *ctx) ((u64)ctx->irqs.range[3] & 0xffff)); } +int cxl_attach_dedicated_process_psl9(struct cxl_context *ctx, u64 wed, u64 amr) +{ + struct cxl_afu *afu = ctx->afu; + int result; + + /* fill the process element entry */ + result = process_element_entry(ctx, wed, amr); + if (result) + return result; + + if (ctx->afu->adapter->native->sl_ops->update_dedicated_ivtes) + afu->adapter->native->sl_ops->update_dedicated_ivtes(ctx); + + result = cxl_ops->afu_reset(afu); + if (result) + return result; + + return afu_enable(afu); +} + int cxl_attach_dedicated_process_psl8(struct cxl_context *ctx, u64 wed, u64 amr) { struct cxl_afu *afu = ctx->afu; @@ -892,6 +1055,21 @@ static int native_get_irq_info(struct cxl_afu *afu, struct cxl_irq_info *info) return 0; } +void cxl_native_irq_dump_regs_psl9(struct cxl_context *ctx) +{ + u64 fir1, fir2, serr; + + fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR1); + fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL9_FIR2); + + dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); + dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); + if (ctx->afu->adapter->native->sl_ops->register_serr_irq) { + serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); + cxl_afu_decode_psl_serr(ctx->afu, serr); + } +} + void cxl_native_irq_dump_regs_psl8(struct cxl_context *ctx) { u64 fir1, fir2, fir_slice, serr, afu_debug; @@ -928,9 +1106,20 @@ static irqreturn_t native_handle_psl_slice_error(struct cxl_context *ctx, return cxl_ops->ack_irq(ctx, 0, errstat); } +static bool cxl_is_translation_fault(struct cxl_afu *afu, u64 dsisr) +{ + if ((cxl_is_psl8(afu)) && (dsisr & CXL_PSL_DSISR_TRANS)) + return true; + + if ((cxl_is_psl9(afu)) && (dsisr & CXL_PSL9_DSISR_An_TF)) + return true; + + return false; +} + irqreturn_t cxl_fail_irq_psl(struct cxl_afu *afu, struct cxl_irq_info *irq_info) { - if (irq_info->dsisr & CXL_PSL_DSISR_TRANS) + if (cxl_is_translation_fault(afu, irq_info->dsisr)) cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); else cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); @@ -1001,6 +1190,9 @@ static void native_irq_wait(struct cxl_context *ctx) if (cxl_is_psl8(ctx->afu) && ((dsisr & CXL_PSL_DSISR_PENDING) == 0)) return; + if (cxl_is_psl9(ctx->afu) && + ((dsisr & CXL_PSL9_DSISR_PENDING) == 0)) + return; /* * We are waiting for the workqueue to process our * irq, so need to let that run here. @@ -1127,8 +1319,7 @@ int cxl_native_register_serr_irq(struct cxl_afu *afu) } serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); - if (cxl_is_power8()) - serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); + serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); return 0; diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 360c231..428c80b 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -60,7 +60,7 @@ #define CXL_VSEC_PROTOCOL_MASK 0xe0 #define CXL_VSEC_PROTOCOL_1024TB 0x80 #define CXL_VSEC_PROTOCOL_512TB 0x40 -#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8 uses this */ +#define CXL_VSEC_PROTOCOL_256TB 0x20 /* Power 8/9 uses this */ #define CXL_VSEC_PROTOCOL_ENABLE 0x01 #define CXL_READ_VSEC_PSL_REVISION(dev, vsec, dest) \ @@ -326,14 +326,20 @@ static void dump_afu_descriptor(struct cxl_afu *afu) #define P8_CAPP_UNIT0_ID 0xBA #define P8_CAPP_UNIT1_ID 0XBE +#define P9_CAPP_UNIT0_ID 0xC0 +#define P9_CAPP_UNIT1_ID 0xE0 -static u64 get_capp_unit_id(struct device_node *np) +static u32 get_phb_index(struct device_node *np) { u32 phb_index; if (of_property_read_u32(np, "ibm,phb-index", &phb_index)) - return 0; + return -ENODEV; + return phb_index; +} +static u64 get_capp_unit_id(struct device_node *np, u32 phb_index) +{ /* * POWER 8: * - For chips other than POWER8NVL, we only have CAPP 0, @@ -352,10 +358,25 @@ static u64 get_capp_unit_id(struct device_node *np) return P8_CAPP_UNIT1_ID; } + /* + * POWER 9: + * PEC0 (PHB0). Capp ID = CAPP0 (0b1100_0000) + * PEC1 (PHB1 - PHB2). No capi mode + * PEC2 (PHB3 - PHB4 - PHB5): Capi mode on PHB3 only. Capp ID = CAPP1 (0b1110_0000) + */ + if (cxl_is_power9()) { + if (phb_index == 0) + return P9_CAPP_UNIT0_ID; + + if (phb_index == 3) + return P9_CAPP_UNIT1_ID; + } + return 0; } -static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id) +static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, + u32 *phb_index, u64 *capp_unit_id) { struct device_node *np; const __be32 *prop; @@ -367,8 +388,16 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id np = of_get_next_parent(np); if (!np) return -ENODEV; + *chipid = be32_to_cpup(prop); - *capp_unit_id = get_capp_unit_id(np); + + *phb_index = get_phb_index(np); + if (*phb_index == -ENODEV) { + pr_err("cxl: invalid phb index\n"); + return -ENODEV; + } + + *capp_unit_id = get_capp_unit_id(np, *phb_index); of_node_put(np); if (!*capp_unit_id) { pr_err("cxl: invalid capp unit id\n"); @@ -378,14 +407,97 @@ static int calc_capp_routing(struct pci_dev *dev, u64 *chipid, u64 *capp_unit_id return 0; } +static int init_implementation_adapter_regs_psl9(struct cxl *adapter, struct pci_dev *dev) +{ + u64 xsl_dsnctl, psl_fircntl; + u64 chipid; + u32 phb_index; + u64 capp_unit_id; + int rc; + + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); + if (rc) + return rc; + + /* CAPI Identifier bits [0:7] + * bit 61:60 MSI bits --> 0 + * bit 59 TVT selector --> 0 + */ + /* Tell XSL where to route data to. + * The field chipid should match the PHB CAPI_CMPM register + */ + xsl_dsnctl = ((u64)0x2 << (63-7)); /* Bit 57 */ + xsl_dsnctl |= (capp_unit_id << (63-15)); + + /* nMMU_ID Defaults to: b’000001001’*/ + xsl_dsnctl |= ((u64)0x09 << (63-28)); + + if (cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)) { + /* Used to identify CAPI packets which should be sorted into + * the Non-Blocking queues by the PHB. This field should match + * the PHB PBL_NBW_CMPM register + * nbwind=0x03, bits [57:58], must include capi indicator. + * Not supported on P9 DD1. + */ + xsl_dsnctl |= ((u64)0x03 << (63-47)); + + /* Upper 16b address bits of ASB_Notify messages sent to the + * system. Need to match the PHB’s ASN Compare/Mask Register. + * Not supported on P9 DD1. + */ + xsl_dsnctl |= ((u64)0x04 << (63-55)); + } + + cxl_p1_write(adapter, CXL_XSL9_DSNCTL, xsl_dsnctl); + + /* Set fir_cntl to recommended value for production env */ + psl_fircntl = (0x2ULL << (63-3)); /* ce_report */ + psl_fircntl |= (0x1ULL << (63-6)); /* FIR_report */ + psl_fircntl |= 0x1ULL; /* ce_thresh */ + cxl_p1_write(adapter, CXL_PSL9_FIR_CNTL, psl_fircntl); + + /* vccredits=0x1 pcklat=0x4 */ + cxl_p1_write(adapter, CXL_PSL9_DSNDCTL, 0x0000000000001810ULL); + + /* For debugging with trace arrays. + * Configure RX trace 0 segmented mode. + * Configure CT trace 0 segmented mode. + * Configure LA0 trace 0 segmented mode. + * Configure LA1 trace 0 segmented mode. + */ + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000000ULL); + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000003ULL); + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000005ULL); + cxl_p1_write(adapter, CXL_PSL9_TRACECFG, 0x8040800080000006ULL); + + /* A response to an ASB_Notify request is returned by the + * system as an MMIO write to the address defined in + * the PSL_TNR_ADDR register + */ + /* PSL_TNR_ADDR */ + + /* NORST */ + cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x8000000000000000ULL); + + /* allocate the apc machines */ + cxl_p1_write(adapter, CXL_PSL9_APCDEDTYPE, 0x40000003FFFF0000ULL); + + /* Disable vc dd1 fix */ + if ((cxl_is_power9() && cpu_has_feature(CPU_FTR_POWER9_DD1))) + cxl_p1_write(adapter, CXL_PSL9_GP_CT, 0x0400000000000001ULL); + + return 0; +} + static int init_implementation_adapter_regs_psl8(struct cxl *adapter, struct pci_dev *dev) { u64 psl_dsnctl, psl_fircntl; u64 chipid; + u32 phb_index; u64 capp_unit_id; int rc; - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); if (rc) return rc; @@ -414,10 +526,11 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ { u64 xsl_dsnctl; u64 chipid; + u32 phb_index; u64 capp_unit_id; int rc; - rc = calc_capp_routing(dev, &chipid, &capp_unit_id); + rc = calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id); if (rc) return rc; @@ -435,6 +548,12 @@ static int init_implementation_adapter_regs_xsl(struct cxl *adapter, struct pci_ /* For the PSL this is a multiple for 0 < n <= 7: */ #define PSL_2048_250MHZ_CYCLES 1 +static void write_timebase_ctrl_psl9(struct cxl *adapter) +{ + cxl_p1_write(adapter, CXL_PSL9_TB_CTLSTAT, + TBSYNC_CNT(2 * PSL_2048_250MHZ_CYCLES)); +} + static void write_timebase_ctrl_psl8(struct cxl *adapter) { cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT, @@ -456,6 +575,11 @@ static void write_timebase_ctrl_xsl(struct cxl *adapter) TBSYNC_CNT(XSL_4000_CLOCKS)); } +static u64 timebase_read_psl9(struct cxl *adapter) +{ + return cxl_p1_read(adapter, CXL_PSL9_Timebase); +} + static u64 timebase_read_psl8(struct cxl *adapter) { return cxl_p1_read(adapter, CXL_PSL_Timebase); @@ -514,6 +638,11 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) return; } +static int init_implementation_afu_regs_psl9(struct cxl_afu *afu) +{ + return 0; +} + static int init_implementation_afu_regs_psl8(struct cxl_afu *afu) { /* read/write masks for this slice */ @@ -612,7 +741,7 @@ static int setup_cxl_bars(struct pci_dev *dev) /* * BAR 4/5 has a special meaning for CXL and must be programmed with a * special value corresponding to the CXL protocol address range. - * For POWER 8 that means bits 48:49 must be set to 10 + * For POWER 8/9 that means bits 48:49 must be set to 10 */ pci_write_config_dword(dev, PCI_BASE_ADDRESS_4, 0x00000000); pci_write_config_dword(dev, PCI_BASE_ADDRESS_5, 0x00020000); @@ -997,6 +1126,52 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu) return 0; } +static int sanitise_afu_regs_psl9(struct cxl_afu *afu) +{ + u64 reg; + + /* + * Clear out any regs that contain either an IVTE or address or may be + * waiting on an acknowledgment to try to be a bit safer as we bring + * it online + */ + reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); + if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { + dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg); + if (cxl_ops->afu_reset(afu)) + return -EIO; + if (cxl_afu_disable(afu)) + return -EIO; + if (cxl_psl_purge(afu)) + return -EIO; + } + cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0x0000000000000000); + cxl_p1n_write(afu, CXL_PSL_AMBAR_An, 0x0000000000000000); + reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An); + if (reg) { + dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg); + if (reg & CXL_PSL9_DSISR_An_TF) + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); + else + cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); + } + if (afu->adapter->native->sl_ops->register_serr_irq) { + reg = cxl_p1n_read(afu, CXL_PSL_SERR_An); + if (reg) { + if (reg & ~0x000000007fffffff) + dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg); + cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff); + } + } + reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); + if (reg) { + dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg); + cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg); + } + + return 0; +} + static int sanitise_afu_regs_psl8(struct cxl_afu *afu) { u64 reg; @@ -1254,10 +1429,10 @@ int cxl_pci_reset(struct cxl *adapter) /* * The adapter is about to be reset, so ignore errors. - * Not supported on P9 DD1 but don't forget to enable it - * on P9 DD2 + * Not supported on P9 DD1 */ - if (cxl_is_power8()) + if ((cxl_is_power8()) || + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) cxl_data_cache_flush(adapter); /* pcie_warm_reset requests a fundamental pci reset which includes a @@ -1393,6 +1568,9 @@ static bool cxl_compatible_caia_version(struct cxl *adapter) if (cxl_is_power8() && (adapter->caia_major == 1)) return true; + if (cxl_is_power9() && (adapter->caia_major == 2)) + return true; + return false; } @@ -1460,8 +1638,12 @@ static int sanitise_adapter_regs(struct cxl *adapter) /* Clear PSL tberror bit by writing 1 to it */ cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror); - if (adapter->native->sl_ops->invalidate_all) + if (adapter->native->sl_ops->invalidate_all) { + /* do not invalidate ERAT entries when not reloading on PERST */ + if (cxl_is_power9() && (adapter->perst_loads_image)) + return 0; rc = adapter->native->sl_ops->invalidate_all(adapter); + } return rc; } @@ -1546,6 +1728,30 @@ static void cxl_deconfigure_adapter(struct cxl *adapter) pci_disable_device(pdev); } +static const struct cxl_service_layer_ops psl9_ops = { + .adapter_regs_init = init_implementation_adapter_regs_psl9, + .invalidate_all = cxl_invalidate_all_psl9, + .afu_regs_init = init_implementation_afu_regs_psl9, + .sanitise_afu_regs = sanitise_afu_regs_psl9, + .register_serr_irq = cxl_native_register_serr_irq, + .release_serr_irq = cxl_native_release_serr_irq, + .handle_interrupt = cxl_irq_psl9, + .fail_irq = cxl_fail_irq_psl, + .activate_dedicated_process = cxl_activate_dedicated_process_psl9, + .attach_afu_directed = cxl_attach_afu_directed_psl9, + .attach_dedicated_process = cxl_attach_dedicated_process_psl9, + .update_dedicated_ivtes = cxl_update_dedicated_ivtes_psl9, + .debugfs_add_adapter_regs = cxl_debugfs_add_adapter_regs_psl9, + .debugfs_add_afu_regs = cxl_debugfs_add_afu_regs_psl9, + .psl_irq_dump_registers = cxl_native_irq_dump_regs_psl9, + .err_irq_dump_registers = cxl_native_err_irq_dump_regs, + .debugfs_stop_trace = cxl_stop_trace_psl9, + .write_timebase_ctrl = write_timebase_ctrl_psl9, + .timebase_read = timebase_read_psl9, + .capi_mode = OPAL_PHB_CAPI_MODE_CAPI, + .needs_reset_before_disable = true, +}; + static const struct cxl_service_layer_ops psl8_ops = { .adapter_regs_init = init_implementation_adapter_regs_psl8, .invalidate_all = cxl_invalidate_all_psl8, @@ -1589,6 +1795,9 @@ static void set_sl_ops(struct cxl *adapter, struct pci_dev *dev) if (cxl_is_power8()) { dev_info(&dev->dev, "Device uses a PSL8\n"); adapter->native->sl_ops = &psl8_ops; + } else { + dev_info(&dev->dev, "Device uses a PSL9\n"); + adapter->native->sl_ops = &psl9_ops; } } } @@ -1659,8 +1868,12 @@ static void cxl_pci_remove_adapter(struct cxl *adapter) cxl_sysfs_adapter_remove(adapter); cxl_debugfs_adapter_remove(adapter); - /* Flush adapter datacache as its about to be removed */ - cxl_data_cache_flush(adapter); + /* Flush adapter datacache as its about to be removed. + * Not supported on P9 DD1 + */ + if ((cxl_is_power8()) || + ((cxl_is_power9() && !cpu_has_feature(CPU_FTR_POWER9_DD1)))) + cxl_data_cache_flush(adapter); cxl_deconfigure_adapter(adapter); @@ -1744,6 +1957,11 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } + if (cxl_is_power9() && !radix_enabled()) { + dev_info(&dev->dev, "Only Radix mode supported\n"); + return -ENODEV; + } + if (cxl_verbose) dump_cxl_config_space(dev); diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h index 751d611..b8e300a 100644 --- a/drivers/misc/cxl/trace.h +++ b/drivers/misc/cxl/trace.h @@ -17,6 +17,15 @@ #include "cxl.h" +#define dsisr_psl9_flags(flags) \ + __print_flags(flags, "|", \ + { CXL_PSL9_DSISR_An_CO_MASK, "FR" }, \ + { CXL_PSL9_DSISR_An_TF, "TF" }, \ + { CXL_PSL9_DSISR_An_PE, "PE" }, \ + { CXL_PSL9_DSISR_An_AE, "AE" }, \ + { CXL_PSL9_DSISR_An_OC, "OC" }, \ + { CXL_PSL9_DSISR_An_S, "S" }) + #define DSISR_FLAGS \ { CXL_PSL_DSISR_An_DS, "DS" }, \ { CXL_PSL_DSISR_An_DM, "DM" }, \ @@ -154,6 +163,40 @@ TRACE_EVENT(cxl_afu_irq, ) ); +TRACE_EVENT(cxl_psl9_irq, + TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar), + + TP_ARGS(ctx, irq, dsisr, dar), + + TP_STRUCT__entry( + __field(u8, card) + __field(u8, afu) + __field(u16, pe) + __field(int, irq) + __field(u64, dsisr) + __field(u64, dar) + ), + + TP_fast_assign( + __entry->card = ctx->afu->adapter->adapter_num; + __entry->afu = ctx->afu->slice; + __entry->pe = ctx->pe; + __entry->irq = irq; + __entry->dsisr = dsisr; + __entry->dar = dar; + ), + + TP_printk("afu%i.%i pe=%i irq=%i dsisr=0x%016llx dsisr=%s dar=0x%016llx", + __entry->card, + __entry->afu, + __entry->pe, + __entry->irq, + __entry->dsisr, + dsisr_psl9_flags(__entry->dsisr), + __entry->dar + ) +); + TRACE_EVENT(cxl_psl_irq, TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar),
The new Coherent Accelerator Interface Architecture, level 2, for the IBM POWER9 brings new content and features: - POWER9 Service Layer - Registers - Radix mode - Process element entry - Dedicated-Shared Process Programming Model - Translation Fault Handling - CAPP - Memory Context ID If a valid mm_struct is found the memory context id is used for each transaction associated with the process handle. The PSL uses the context ID to find the corresponding process element. Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com> --- drivers/misc/cxl/context.c | 16 ++- drivers/misc/cxl/cxl.h | 137 +++++++++++++++++++++---- drivers/misc/cxl/debugfs.c | 19 ++++ drivers/misc/cxl/fault.c | 78 ++++++++------ drivers/misc/cxl/guest.c | 8 +- drivers/misc/cxl/irq.c | 53 ++++++++++ drivers/misc/cxl/native.c | 247 ++++++++++++++++++++++++++++++++++++++++----- drivers/misc/cxl/pci.c | 246 +++++++++++++++++++++++++++++++++++++++++--- drivers/misc/cxl/trace.h | 43 ++++++++ 9 files changed, 752 insertions(+), 95 deletions(-)