diff options
Diffstat (limited to 'drivers/misc/cxl/native.c')
-rw-r--r-- | drivers/misc/cxl/native.c | 82 |
1 files changed, 69 insertions, 13 deletions
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index e80d8f7d4dcb..3bcdaee11ba1 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c | |||
@@ -21,10 +21,10 @@ | |||
21 | #include "cxl.h" | 21 | #include "cxl.h" |
22 | #include "trace.h" | 22 | #include "trace.h" |
23 | 23 | ||
24 | static int afu_control(struct cxl_afu *afu, u64 command, | 24 | static int afu_control(struct cxl_afu *afu, u64 command, u64 clear, |
25 | u64 result, u64 mask, bool enabled) | 25 | u64 result, u64 mask, bool enabled) |
26 | { | 26 | { |
27 | u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); | 27 | u64 AFU_Cntl; |
28 | unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); | 28 | unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT); |
29 | int rc = 0; | 29 | int rc = 0; |
30 | 30 | ||
@@ -33,7 +33,8 @@ static int afu_control(struct cxl_afu *afu, u64 command, | |||
33 | 33 | ||
34 | trace_cxl_afu_ctrl(afu, command); | 34 | trace_cxl_afu_ctrl(afu, command); |
35 | 35 | ||
36 | cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command); | 36 | AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); |
37 | cxl_p2n_write(afu, CXL_AFU_Cntl_An, (AFU_Cntl & ~clear) | command); | ||
37 | 38 | ||
38 | AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); | 39 | AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); |
39 | while ((AFU_Cntl & mask) != result) { | 40 | while ((AFU_Cntl & mask) != result) { |
@@ -54,6 +55,16 @@ static int afu_control(struct cxl_afu *afu, u64 command, | |||
54 | cpu_relax(); | 55 | cpu_relax(); |
55 | AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); | 56 | AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); |
56 | }; | 57 | }; |
58 | |||
59 | if (AFU_Cntl & CXL_AFU_Cntl_An_RA) { | ||
60 | /* | ||
61 | * Workaround for a bug in the XSL used in the Mellanox CX4 | ||
62 | * that fails to clear the RA bit after an AFU reset, | ||
63 | * preventing subsequent AFU resets from working. | ||
64 | */ | ||
65 | cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl & ~CXL_AFU_Cntl_An_RA); | ||
66 | } | ||
67 | |||
57 | pr_devel("AFU command complete: %llx\n", command); | 68 | pr_devel("AFU command complete: %llx\n", command); |
58 | afu->enabled = enabled; | 69 | afu->enabled = enabled; |
59 | out: | 70 | out: |
@@ -67,7 +78,7 @@ static int afu_enable(struct cxl_afu *afu) | |||
67 | { | 78 | { |
68 | pr_devel("AFU enable request\n"); | 79 | pr_devel("AFU enable request\n"); |
69 | 80 | ||
70 | return afu_control(afu, CXL_AFU_Cntl_An_E, | 81 | return afu_control(afu, CXL_AFU_Cntl_An_E, 0, |
71 | CXL_AFU_Cntl_An_ES_Enabled, | 82 | CXL_AFU_Cntl_An_ES_Enabled, |
72 | CXL_AFU_Cntl_An_ES_MASK, true); | 83 | CXL_AFU_Cntl_An_ES_MASK, true); |
73 | } | 84 | } |
@@ -76,7 +87,8 @@ int cxl_afu_disable(struct cxl_afu *afu) | |||
76 | { | 87 | { |
77 | pr_devel("AFU disable request\n"); | 88 | pr_devel("AFU disable request\n"); |
78 | 89 | ||
79 | return afu_control(afu, 0, CXL_AFU_Cntl_An_ES_Disabled, | 90 | return afu_control(afu, 0, CXL_AFU_Cntl_An_E, |
91 | CXL_AFU_Cntl_An_ES_Disabled, | ||
80 | CXL_AFU_Cntl_An_ES_MASK, false); | 92 | CXL_AFU_Cntl_An_ES_MASK, false); |
81 | } | 93 | } |
82 | 94 | ||
@@ -85,7 +97,7 @@ static int native_afu_reset(struct cxl_afu *afu) | |||
85 | { | 97 | { |
86 | pr_devel("AFU reset request\n"); | 98 | pr_devel("AFU reset request\n"); |
87 | 99 | ||
88 | return afu_control(afu, CXL_AFU_Cntl_An_RA, | 100 | return afu_control(afu, CXL_AFU_Cntl_An_RA, 0, |
89 | CXL_AFU_Cntl_An_RS_Complete | CXL_AFU_Cntl_An_ES_Disabled, | 101 | CXL_AFU_Cntl_An_RS_Complete | CXL_AFU_Cntl_An_ES_Disabled, |
90 | CXL_AFU_Cntl_An_RS_MASK | CXL_AFU_Cntl_An_ES_MASK, | 102 | CXL_AFU_Cntl_An_RS_MASK | CXL_AFU_Cntl_An_ES_MASK, |
91 | false); | 103 | false); |
@@ -189,7 +201,7 @@ int cxl_alloc_spa(struct cxl_afu *afu) | |||
189 | unsigned spa_size; | 201 | unsigned spa_size; |
190 | 202 | ||
191 | /* Work out how many pages to allocate */ | 203 | /* Work out how many pages to allocate */ |
192 | afu->native->spa_order = 0; | 204 | afu->native->spa_order = -1; |
193 | do { | 205 | do { |
194 | afu->native->spa_order++; | 206 | afu->native->spa_order++; |
195 | spa_size = (1 << afu->native->spa_order) * PAGE_SIZE; | 207 | spa_size = (1 << afu->native->spa_order) * PAGE_SIZE; |
@@ -595,7 +607,33 @@ static int deactivate_afu_directed(struct cxl_afu *afu) | |||
595 | cxl_sysfs_afu_m_remove(afu); | 607 | cxl_sysfs_afu_m_remove(afu); |
596 | cxl_chardev_afu_remove(afu); | 608 | cxl_chardev_afu_remove(afu); |
597 | 609 | ||
598 | cxl_ops->afu_reset(afu); | 610 | /* |
611 | * The CAIA section 2.2.1 indicates that the procedure for starting and | ||
612 | * stopping an AFU in AFU directed mode is AFU specific, which is not | ||
613 | * ideal since this code is generic and with one exception has no | ||
614 | * knowledge of the AFU. This is in contrast to the procedure for | ||
615 | * disabling a dedicated process AFU, which is documented to just | ||
616 | * require a reset. The architecture does indicate that both an AFU | ||
617 | * reset and an AFU disable should result in the AFU being disabled and | ||
618 | * we do both followed by a PSL purge for safety. | ||
619 | * | ||
620 | * Notably we used to have some issues with the disable sequence on PSL | ||
621 | * cards, which is why we ended up using this heavy weight procedure in | ||
622 | * the first place, however a bug was discovered that had rendered the | ||
623 | * disable operation ineffective, so it is conceivable that was the | ||
624 | * sole explanation for those difficulties. Careful regression testing | ||
625 | * is recommended if anyone attempts to remove or reorder these | ||
626 | * operations. | ||
627 | * | ||
628 | * The XSL on the Mellanox CX4 behaves a little differently from the | ||
629 | * PSL based cards and will time out an AFU reset if the AFU is still | ||
630 | * enabled. That card is special in that we do have a means to identify | ||
631 | * it from this code, so in that case we skip the reset and just use a | ||
632 | * disable/purge to avoid the timeout and corresponding noise in the | ||
633 | * kernel log. | ||
634 | */ | ||
635 | if (afu->adapter->native->sl_ops->needs_reset_before_disable) | ||
636 | cxl_ops->afu_reset(afu); | ||
599 | cxl_afu_disable(afu); | 637 | cxl_afu_disable(afu); |
600 | cxl_psl_purge(afu); | 638 | cxl_psl_purge(afu); |
601 | 639 | ||
@@ -735,6 +773,22 @@ static int native_attach_process(struct cxl_context *ctx, bool kernel, | |||
735 | 773 | ||
736 | static inline int detach_process_native_dedicated(struct cxl_context *ctx) | 774 | static inline int detach_process_native_dedicated(struct cxl_context *ctx) |
737 | { | 775 | { |
776 | /* | ||
777 | * The CAIA section 2.1.1 indicates that we need to do an AFU reset to | ||
778 | * stop the AFU in dedicated mode (we therefore do not make that | ||
779 | * optional like we do in the afu directed path). It does not indicate | ||
780 | * that we need to do an explicit disable (which should occur | ||
781 | * implicitly as part of the reset) or purge, but we do these as well | ||
782 | * to be on the safe side. | ||
783 | * | ||
784 | * Notably we used to have some issues with the disable sequence | ||
785 | * (before the sequence was spelled out in the architecture) which is | ||
786 | * why we were so heavy weight in the first place, however a bug was | ||
787 | * discovered that had rendered the disable operation ineffective, so | ||
788 | * it is conceivable that was the sole explanation for those | ||
789 | * difficulties. Point is, we should be careful and do some regression | ||
790 | * testing if we ever attempt to remove any part of this procedure. | ||
791 | */ | ||
738 | cxl_ops->afu_reset(ctx->afu); | 792 | cxl_ops->afu_reset(ctx->afu); |
739 | cxl_afu_disable(ctx->afu); | 793 | cxl_afu_disable(ctx->afu); |
740 | cxl_psl_purge(ctx->afu); | 794 | cxl_psl_purge(ctx->afu); |
@@ -808,7 +862,7 @@ void cxl_native_psl_irq_dump_regs(struct cxl_context *ctx) | |||
808 | dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); | 862 | dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); |
809 | if (ctx->afu->adapter->native->sl_ops->register_serr_irq) { | 863 | if (ctx->afu->adapter->native->sl_ops->register_serr_irq) { |
810 | serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); | 864 | serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); |
811 | dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); | 865 | cxl_afu_decode_psl_serr(ctx->afu, serr); |
812 | } | 866 | } |
813 | dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); | 867 | dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); |
814 | dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); | 868 | dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); |
@@ -902,21 +956,23 @@ void native_irq_wait(struct cxl_context *ctx) | |||
902 | static irqreturn_t native_slice_irq_err(int irq, void *data) | 956 | static irqreturn_t native_slice_irq_err(int irq, void *data) |
903 | { | 957 | { |
904 | struct cxl_afu *afu = data; | 958 | struct cxl_afu *afu = data; |
905 | u64 fir_slice, errstat, serr, afu_debug; | 959 | u64 fir_slice, errstat, serr, afu_debug, afu_error, dsisr; |
906 | 960 | ||
907 | /* | 961 | /* |
908 | * slice err interrupt is only used with full PSL (no XSL) | 962 | * slice err interrupt is only used with full PSL (no XSL) |
909 | */ | 963 | */ |
910 | WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq); | ||
911 | |||
912 | serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); | 964 | serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); |
913 | fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); | 965 | fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); |
914 | errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); | 966 | errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); |
915 | afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); | 967 | afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); |
916 | dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); | 968 | afu_error = cxl_p2n_read(afu, CXL_AFU_ERR_An); |
969 | dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); | ||
970 | cxl_afu_decode_psl_serr(afu, serr); | ||
917 | dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); | 971 | dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); |
918 | dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat); | 972 | dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat); |
919 | dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); | 973 | dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); |
974 | dev_crit(&afu->dev, "AFU_ERR_An: 0x%.16llx\n", afu_error); | ||
975 | dev_crit(&afu->dev, "PSL_DSISR_An: 0x%.16llx\n", dsisr); | ||
920 | 976 | ||
921 | cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); | 977 | cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); |
922 | 978 | ||