diff options
author | Frederic Barrat <fbarrat@linux.vnet.ibm.com> | 2016-03-04 06:26:26 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2016-03-08 21:05:39 -0500 |
commit | d56d301b51746e71f7bdaaba10973f054c3c736e (patch) | |
tree | cf1ec59764c3012335d55d5ed620a1973e6b3f6c /drivers/misc/cxl/native.c | |
parent | 8633186209e35dfafc27c3d0f0d5e702ab47265f (diff) |
cxl: Move bare-metal specific code to specialized files
Move a few functions around to better separate code specific to
bare-metal environment from code which will be commonly used between
guest and bare-metal.
Code specific to bare-metal is meant to be in native.c or pci.c
only. It's basically anything which touches the card p1 registers,
some p2 registers not needed from a guest and the PCI interface.
Co-authored-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
Signed-off-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
Reviewed-by: Manoj Kumar <manoj@linux.vnet.ibm.com>
Acked-by: Ian Munsie <imunsie@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/misc/cxl/native.c')
-rw-r--r-- | drivers/misc/cxl/native.c | 240 |
1 files changed, 239 insertions, 1 deletions
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 0b0a4c8a27d0..3103e3327ea6 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c | |||
@@ -712,7 +712,7 @@ int cxl_detach_process(struct cxl_context *ctx) | |||
712 | return detach_process_native_afu_directed(ctx); | 712 | return detach_process_native_afu_directed(ctx); |
713 | } | 713 | } |
714 | 714 | ||
715 | int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info) | 715 | static int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info) |
716 | { | 716 | { |
717 | u64 pidtid; | 717 | u64 pidtid; |
718 | 718 | ||
@@ -734,6 +734,208 @@ int cxl_get_irq(struct cxl_afu *afu, struct cxl_irq_info *info) | |||
734 | return 0; | 734 | return 0; |
735 | } | 735 | } |
736 | 736 | ||
737 | irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat) | ||
738 | { | ||
739 | u64 fir1, fir2, fir_slice, serr, afu_debug; | ||
740 | |||
741 | fir1 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR1); | ||
742 | fir2 = cxl_p1_read(ctx->afu->adapter, CXL_PSL_FIR2); | ||
743 | fir_slice = cxl_p1n_read(ctx->afu, CXL_PSL_FIR_SLICE_An); | ||
744 | serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); | ||
745 | afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An); | ||
746 | |||
747 | dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat); | ||
748 | dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); | ||
749 | dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); | ||
750 | dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); | ||
751 | dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); | ||
752 | dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); | ||
753 | |||
754 | dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n"); | ||
755 | cxl_stop_trace(ctx->afu->adapter); | ||
756 | |||
757 | return cxl_ack_irq(ctx, 0, errstat); | ||
758 | } | ||
759 | |||
760 | static irqreturn_t fail_psl_irq(struct cxl_afu *afu, struct cxl_irq_info *irq_info) | ||
761 | { | ||
762 | if (irq_info->dsisr & CXL_PSL_DSISR_TRANS) | ||
763 | cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); | ||
764 | else | ||
765 | cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); | ||
766 | |||
767 | return IRQ_HANDLED; | ||
768 | } | ||
769 | |||
770 | static irqreturn_t cxl_irq_multiplexed(int irq, void *data) | ||
771 | { | ||
772 | struct cxl_afu *afu = data; | ||
773 | struct cxl_context *ctx; | ||
774 | struct cxl_irq_info irq_info; | ||
775 | int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff; | ||
776 | int ret; | ||
777 | |||
778 | if ((ret = cxl_get_irq(afu, &irq_info))) { | ||
779 | WARN(1, "Unable to get CXL IRQ Info: %i\n", ret); | ||
780 | return fail_psl_irq(afu, &irq_info); | ||
781 | } | ||
782 | |||
783 | rcu_read_lock(); | ||
784 | ctx = idr_find(&afu->contexts_idr, ph); | ||
785 | if (ctx) { | ||
786 | ret = cxl_irq(irq, ctx, &irq_info); | ||
787 | rcu_read_unlock(); | ||
788 | return ret; | ||
789 | } | ||
790 | rcu_read_unlock(); | ||
791 | |||
792 | WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR" | ||
793 | " %016llx\n(Possible AFU HW issue - was a term/remove acked" | ||
794 | " with outstanding transactions?)\n", ph, irq_info.dsisr, | ||
795 | irq_info.dar); | ||
796 | return fail_psl_irq(afu, &irq_info); | ||
797 | } | ||
798 | |||
799 | static irqreturn_t cxl_slice_irq_err(int irq, void *data) | ||
800 | { | ||
801 | struct cxl_afu *afu = data; | ||
802 | u64 fir_slice, errstat, serr, afu_debug; | ||
803 | |||
804 | WARN(irq, "CXL SLICE ERROR interrupt %i\n", irq); | ||
805 | |||
806 | serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); | ||
807 | fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); | ||
808 | errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); | ||
809 | afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); | ||
810 | dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); | ||
811 | dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); | ||
812 | dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat); | ||
813 | dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); | ||
814 | |||
815 | cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); | ||
816 | |||
817 | return IRQ_HANDLED; | ||
818 | } | ||
819 | |||
820 | static irqreturn_t cxl_irq_err(int irq, void *data) | ||
821 | { | ||
822 | struct cxl *adapter = data; | ||
823 | u64 fir1, fir2, err_ivte; | ||
824 | |||
825 | WARN(1, "CXL ERROR interrupt %i\n", irq); | ||
826 | |||
827 | err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE); | ||
828 | dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte); | ||
829 | |||
830 | dev_crit(&adapter->dev, "STOPPING CXL TRACE\n"); | ||
831 | cxl_stop_trace(adapter); | ||
832 | |||
833 | fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1); | ||
834 | fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2); | ||
835 | |||
836 | dev_crit(&adapter->dev, "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n", fir1, fir2); | ||
837 | |||
838 | return IRQ_HANDLED; | ||
839 | } | ||
840 | |||
841 | int cxl_register_psl_err_irq(struct cxl *adapter) | ||
842 | { | ||
843 | int rc; | ||
844 | |||
845 | adapter->irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err", | ||
846 | dev_name(&adapter->dev)); | ||
847 | if (!adapter->irq_name) | ||
848 | return -ENOMEM; | ||
849 | |||
850 | if ((rc = cxl_register_one_irq(adapter, cxl_irq_err, adapter, | ||
851 | &adapter->err_hwirq, | ||
852 | &adapter->err_virq, | ||
853 | adapter->irq_name))) { | ||
854 | kfree(adapter->irq_name); | ||
855 | adapter->irq_name = NULL; | ||
856 | return rc; | ||
857 | } | ||
858 | |||
859 | cxl_p1_write(adapter, CXL_PSL_ErrIVTE, adapter->err_hwirq & 0xffff); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | void cxl_release_psl_err_irq(struct cxl *adapter) | ||
865 | { | ||
866 | if (adapter->err_virq != irq_find_mapping(NULL, adapter->err_hwirq)) | ||
867 | return; | ||
868 | |||
869 | cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000); | ||
870 | cxl_unmap_irq(adapter->err_virq, adapter); | ||
871 | cxl_release_one_irq(adapter, adapter->err_hwirq); | ||
872 | kfree(adapter->irq_name); | ||
873 | } | ||
874 | |||
875 | int cxl_register_serr_irq(struct cxl_afu *afu) | ||
876 | { | ||
877 | u64 serr; | ||
878 | int rc; | ||
879 | |||
880 | afu->err_irq_name = kasprintf(GFP_KERNEL, "cxl-%s-err", | ||
881 | dev_name(&afu->dev)); | ||
882 | if (!afu->err_irq_name) | ||
883 | return -ENOMEM; | ||
884 | |||
885 | if ((rc = cxl_register_one_irq(afu->adapter, cxl_slice_irq_err, afu, | ||
886 | &afu->serr_hwirq, | ||
887 | &afu->serr_virq, afu->err_irq_name))) { | ||
888 | kfree(afu->err_irq_name); | ||
889 | afu->err_irq_name = NULL; | ||
890 | return rc; | ||
891 | } | ||
892 | |||
893 | serr = cxl_p1n_read(afu, CXL_PSL_SERR_An); | ||
894 | serr = (serr & 0x00ffffffffff0000ULL) | (afu->serr_hwirq & 0xffff); | ||
895 | cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | void cxl_release_serr_irq(struct cxl_afu *afu) | ||
901 | { | ||
902 | if (afu->serr_virq != irq_find_mapping(NULL, afu->serr_hwirq)) | ||
903 | return; | ||
904 | |||
905 | cxl_p1n_write(afu, CXL_PSL_SERR_An, 0x0000000000000000); | ||
906 | cxl_unmap_irq(afu->serr_virq, afu); | ||
907 | cxl_release_one_irq(afu->adapter, afu->serr_hwirq); | ||
908 | kfree(afu->err_irq_name); | ||
909 | } | ||
910 | |||
911 | int cxl_register_psl_irq(struct cxl_afu *afu) | ||
912 | { | ||
913 | int rc; | ||
914 | |||
915 | afu->psl_irq_name = kasprintf(GFP_KERNEL, "cxl-%s", | ||
916 | dev_name(&afu->dev)); | ||
917 | if (!afu->psl_irq_name) | ||
918 | return -ENOMEM; | ||
919 | |||
920 | if ((rc = cxl_register_one_irq(afu->adapter, cxl_irq_multiplexed, afu, | ||
921 | &afu->psl_hwirq, &afu->psl_virq, | ||
922 | afu->psl_irq_name))) { | ||
923 | kfree(afu->psl_irq_name); | ||
924 | afu->psl_irq_name = NULL; | ||
925 | } | ||
926 | return rc; | ||
927 | } | ||
928 | |||
929 | void cxl_release_psl_irq(struct cxl_afu *afu) | ||
930 | { | ||
931 | if (afu->psl_virq != irq_find_mapping(NULL, afu->psl_hwirq)) | ||
932 | return; | ||
933 | |||
934 | cxl_unmap_irq(afu->psl_virq, afu); | ||
935 | cxl_release_one_irq(afu->adapter, afu->psl_hwirq); | ||
936 | kfree(afu->psl_irq_name); | ||
937 | } | ||
938 | |||
737 | static void recover_psl_err(struct cxl_afu *afu, u64 errstat) | 939 | static void recover_psl_err(struct cxl_afu *afu, u64 errstat) |
738 | { | 940 | { |
739 | u64 dsisr; | 941 | u64 dsisr; |
@@ -763,3 +965,39 @@ int cxl_check_error(struct cxl_afu *afu) | |||
763 | { | 965 | { |
764 | return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL); | 966 | return (cxl_p1n_read(afu, CXL_PSL_SCNTL_An) == ~0ULL); |
765 | } | 967 | } |
968 | |||
969 | u64 cxl_afu_cr_read64(struct cxl_afu *afu, int cr, u64 off) | ||
970 | { | ||
971 | if (likely(cxl_adapter_link_ok(afu->adapter))) | ||
972 | return in_le64((afu)->afu_desc_mmio + (afu)->crs_offset + | ||
973 | ((cr) * (afu)->crs_len) + (off)); | ||
974 | else | ||
975 | return ~0ULL; | ||
976 | } | ||
977 | |||
978 | u32 cxl_afu_cr_read32(struct cxl_afu *afu, int cr, u64 off) | ||
979 | { | ||
980 | if (likely(cxl_adapter_link_ok(afu->adapter))) | ||
981 | return in_le32((afu)->afu_desc_mmio + (afu)->crs_offset + | ||
982 | ((cr) * (afu)->crs_len) + (off)); | ||
983 | else | ||
984 | return 0xffffffff; | ||
985 | } | ||
986 | |||
987 | u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off) | ||
988 | { | ||
989 | u64 aligned_off = off & ~0x3L; | ||
990 | u32 val; | ||
991 | |||
992 | val = cxl_afu_cr_read32(afu, cr, aligned_off); | ||
993 | return (val >> ((off & 0x2) * 8)) & 0xffff; | ||
994 | } | ||
995 | |||
996 | u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off) | ||
997 | { | ||
998 | u64 aligned_off = off & ~0x3L; | ||
999 | u32 val; | ||
1000 | |||
1001 | val = cxl_afu_cr_read32(afu, cr, aligned_off); | ||
1002 | return (val >> ((off & 0x3) * 8)) & 0xff; | ||
1003 | } | ||