diff options
author | Jiri Kosina <jkosina@suse.cz> | 2015-09-01 09:35:24 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-09-01 09:35:24 -0400 |
commit | 067e2601d3c076abbf45db91261f9065eaa879b2 (patch) | |
tree | 86c8d4b913873dbd3b4ff23562a3a8597984b4df /drivers/misc/cxl/pci.c | |
parent | 3e097d1271ecdff2f251a54ddfc5eaa1f9821e96 (diff) | |
parent | 931830aa5c251e0803523213428f777a48bde254 (diff) |
Merge branch 'for-4.3/gembird' into for-linus
Diffstat (limited to 'drivers/misc/cxl/pci.c')
-rw-r--r-- | drivers/misc/cxl/pci.c | 131 |
1 files changed, 105 insertions, 26 deletions
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 1ef01647265f..32ad09705949 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c | |||
@@ -90,6 +90,7 @@ | |||
90 | /* This works a little different than the p1/p2 register accesses to make it | 90 | /* This works a little different than the p1/p2 register accesses to make it |
91 | * easier to pull out individual fields */ | 91 | * easier to pull out individual fields */ |
92 | #define AFUD_READ(afu, off) in_be64(afu->afu_desc_mmio + off) | 92 | #define AFUD_READ(afu, off) in_be64(afu->afu_desc_mmio + off) |
93 | #define AFUD_READ_LE(afu, off) in_le64(afu->afu_desc_mmio + off) | ||
93 | #define EXTRACT_PPC_BIT(val, bit) (!!(val & PPC_BIT(bit))) | 94 | #define EXTRACT_PPC_BIT(val, bit) (!!(val & PPC_BIT(bit))) |
94 | #define EXTRACT_PPC_BITS(val, bs, be) ((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be)) | 95 | #define EXTRACT_PPC_BITS(val, bs, be) ((val & PPC_BITMASK(bs, be)) >> PPC_BITLSHIFT(be)) |
95 | 96 | ||
@@ -204,7 +205,7 @@ static void dump_cxl_config_space(struct pci_dev *dev) | |||
204 | dev_info(&dev->dev, "p1 regs: %#llx, len: %#llx\n", | 205 | dev_info(&dev->dev, "p1 regs: %#llx, len: %#llx\n", |
205 | p1_base(dev), p1_size(dev)); | 206 | p1_base(dev), p1_size(dev)); |
206 | dev_info(&dev->dev, "p2 regs: %#llx, len: %#llx\n", | 207 | dev_info(&dev->dev, "p2 regs: %#llx, len: %#llx\n", |
207 | p1_base(dev), p2_size(dev)); | 208 | p2_base(dev), p2_size(dev)); |
208 | dev_info(&dev->dev, "BAR 4/5: %#llx, len: %#llx\n", | 209 | dev_info(&dev->dev, "BAR 4/5: %#llx, len: %#llx\n", |
209 | pci_resource_start(dev, 4), pci_resource_len(dev, 4)); | 210 | pci_resource_start(dev, 4), pci_resource_len(dev, 4)); |
210 | 211 | ||
@@ -286,7 +287,8 @@ static void dump_cxl_config_space(struct pci_dev *dev) | |||
286 | 287 | ||
287 | static void dump_afu_descriptor(struct cxl_afu *afu) | 288 | static void dump_afu_descriptor(struct cxl_afu *afu) |
288 | { | 289 | { |
289 | u64 val; | 290 | u64 val, afu_cr_num, afu_cr_off, afu_cr_len; |
291 | int i; | ||
290 | 292 | ||
291 | #define show_reg(name, what) \ | 293 | #define show_reg(name, what) \ |
292 | dev_info(&afu->dev, "afu desc: %30s: %#llx\n", name, what) | 294 | dev_info(&afu->dev, "afu desc: %30s: %#llx\n", name, what) |
@@ -296,6 +298,7 @@ static void dump_afu_descriptor(struct cxl_afu *afu) | |||
296 | show_reg("num_of_processes", AFUD_NUM_PROCS(val)); | 298 | show_reg("num_of_processes", AFUD_NUM_PROCS(val)); |
297 | show_reg("num_of_afu_CRs", AFUD_NUM_CRS(val)); | 299 | show_reg("num_of_afu_CRs", AFUD_NUM_CRS(val)); |
298 | show_reg("req_prog_mode", val & 0xffffULL); | 300 | show_reg("req_prog_mode", val & 0xffffULL); |
301 | afu_cr_num = AFUD_NUM_CRS(val); | ||
299 | 302 | ||
300 | val = AFUD_READ(afu, 0x8); | 303 | val = AFUD_READ(afu, 0x8); |
301 | show_reg("Reserved", val); | 304 | show_reg("Reserved", val); |
@@ -307,8 +310,10 @@ static void dump_afu_descriptor(struct cxl_afu *afu) | |||
307 | val = AFUD_READ_CR(afu); | 310 | val = AFUD_READ_CR(afu); |
308 | show_reg("Reserved", (val >> (63-7)) & 0xff); | 311 | show_reg("Reserved", (val >> (63-7)) & 0xff); |
309 | show_reg("AFU_CR_len", AFUD_CR_LEN(val)); | 312 | show_reg("AFU_CR_len", AFUD_CR_LEN(val)); |
313 | afu_cr_len = AFUD_CR_LEN(val) * 256; | ||
310 | 314 | ||
311 | val = AFUD_READ_CR_OFF(afu); | 315 | val = AFUD_READ_CR_OFF(afu); |
316 | afu_cr_off = val; | ||
312 | show_reg("AFU_CR_offset", val); | 317 | show_reg("AFU_CR_offset", val); |
313 | 318 | ||
314 | val = AFUD_READ_PPPSA(afu); | 319 | val = AFUD_READ_PPPSA(afu); |
@@ -325,6 +330,11 @@ static void dump_afu_descriptor(struct cxl_afu *afu) | |||
325 | val = AFUD_READ_EB_OFF(afu); | 330 | val = AFUD_READ_EB_OFF(afu); |
326 | show_reg("AFU_EB_offset", val); | 331 | show_reg("AFU_EB_offset", val); |
327 | 332 | ||
333 | for (i = 0; i < afu_cr_num; i++) { | ||
334 | val = AFUD_READ_LE(afu, afu_cr_off + i * afu_cr_len); | ||
335 | show_reg("CR Vendor", val & 0xffff); | ||
336 | show_reg("CR Device", (val >> 16) & 0xffff); | ||
337 | } | ||
328 | #undef show_reg | 338 | #undef show_reg |
329 | } | 339 | } |
330 | 340 | ||
@@ -529,7 +539,7 @@ err: | |||
529 | 539 | ||
530 | static void cxl_unmap_slice_regs(struct cxl_afu *afu) | 540 | static void cxl_unmap_slice_regs(struct cxl_afu *afu) |
531 | { | 541 | { |
532 | if (afu->p1n_mmio) | 542 | if (afu->p2n_mmio) |
533 | iounmap(afu->p2n_mmio); | 543 | iounmap(afu->p2n_mmio); |
534 | if (afu->p1n_mmio) | 544 | if (afu->p1n_mmio) |
535 | iounmap(afu->p1n_mmio); | 545 | iounmap(afu->p1n_mmio); |
@@ -593,6 +603,22 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu) | |||
593 | afu->crs_len = AFUD_CR_LEN(val) * 256; | 603 | afu->crs_len = AFUD_CR_LEN(val) * 256; |
594 | afu->crs_offset = AFUD_READ_CR_OFF(afu); | 604 | afu->crs_offset = AFUD_READ_CR_OFF(afu); |
595 | 605 | ||
606 | |||
607 | /* eb_len is in multiple of 4K */ | ||
608 | afu->eb_len = AFUD_EB_LEN(AFUD_READ_EB(afu)) * 4096; | ||
609 | afu->eb_offset = AFUD_READ_EB_OFF(afu); | ||
610 | |||
611 | /* eb_off is 4K aligned so lower 12 bits are always zero */ | ||
612 | if (EXTRACT_PPC_BITS(afu->eb_offset, 0, 11) != 0) { | ||
613 | dev_warn(&afu->dev, | ||
614 | "Invalid AFU error buffer offset %Lx\n", | ||
615 | afu->eb_offset); | ||
616 | dev_info(&afu->dev, | ||
617 | "Ignoring AFU error buffer in the descriptor\n"); | ||
618 | /* indicate that no afu buffer exists */ | ||
619 | afu->eb_len = 0; | ||
620 | } | ||
621 | |||
596 | return 0; | 622 | return 0; |
597 | } | 623 | } |
598 | 624 | ||
@@ -631,7 +657,7 @@ static int sanitise_afu_regs(struct cxl_afu *afu) | |||
631 | reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); | 657 | reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); |
632 | if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { | 658 | if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { |
633 | dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#.16llx\n", reg); | 659 | dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#.16llx\n", reg); |
634 | if (cxl_afu_reset(afu)) | 660 | if (__cxl_afu_reset(afu)) |
635 | return -EIO; | 661 | return -EIO; |
636 | if (cxl_afu_disable(afu)) | 662 | if (cxl_afu_disable(afu)) |
637 | return -EIO; | 663 | return -EIO; |
@@ -672,6 +698,50 @@ static int sanitise_afu_regs(struct cxl_afu *afu) | |||
672 | return 0; | 698 | return 0; |
673 | } | 699 | } |
674 | 700 | ||
701 | #define ERR_BUFF_MAX_COPY_SIZE PAGE_SIZE | ||
702 | /* | ||
703 | * afu_eb_read: | ||
704 | * Called from sysfs and reads the afu error info buffer. The h/w only supports | ||
705 | * 4/8 bytes aligned access. So in case the requested offset/count arent 8 byte | ||
706 | * aligned the function uses a bounce buffer which can be max PAGE_SIZE. | ||
707 | */ | ||
708 | ssize_t cxl_afu_read_err_buffer(struct cxl_afu *afu, char *buf, | ||
709 | loff_t off, size_t count) | ||
710 | { | ||
711 | loff_t aligned_start, aligned_end; | ||
712 | size_t aligned_length; | ||
713 | void *tbuf; | ||
714 | const void __iomem *ebuf = afu->afu_desc_mmio + afu->eb_offset; | ||
715 | |||
716 | if (count == 0 || off < 0 || (size_t)off >= afu->eb_len) | ||
717 | return 0; | ||
718 | |||
719 | /* calculate aligned read window */ | ||
720 | count = min((size_t)(afu->eb_len - off), count); | ||
721 | aligned_start = round_down(off, 8); | ||
722 | aligned_end = round_up(off + count, 8); | ||
723 | aligned_length = aligned_end - aligned_start; | ||
724 | |||
725 | /* max we can copy in one read is PAGE_SIZE */ | ||
726 | if (aligned_length > ERR_BUFF_MAX_COPY_SIZE) { | ||
727 | aligned_length = ERR_BUFF_MAX_COPY_SIZE; | ||
728 | count = ERR_BUFF_MAX_COPY_SIZE - (off & 0x7); | ||
729 | } | ||
730 | |||
731 | /* use bounce buffer for copy */ | ||
732 | tbuf = (void *)__get_free_page(GFP_TEMPORARY); | ||
733 | if (!tbuf) | ||
734 | return -ENOMEM; | ||
735 | |||
736 | /* perform aligned read from the mmio region */ | ||
737 | memcpy_fromio(tbuf, ebuf + aligned_start, aligned_length); | ||
738 | memcpy(buf, tbuf + (off & 0x7), count); | ||
739 | |||
740 | free_page((unsigned long)tbuf); | ||
741 | |||
742 | return count; | ||
743 | } | ||
744 | |||
675 | static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) | 745 | static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) |
676 | { | 746 | { |
677 | struct cxl_afu *afu; | 747 | struct cxl_afu *afu; |
@@ -691,7 +761,7 @@ static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) | |||
691 | goto err2; | 761 | goto err2; |
692 | 762 | ||
693 | /* We need to reset the AFU before we can read the AFU descriptor */ | 763 | /* We need to reset the AFU before we can read the AFU descriptor */ |
694 | if ((rc = cxl_afu_reset(afu))) | 764 | if ((rc = __cxl_afu_reset(afu))) |
695 | goto err2; | 765 | goto err2; |
696 | 766 | ||
697 | if (cxl_verbose) | 767 | if (cxl_verbose) |
@@ -731,6 +801,9 @@ static int cxl_init_afu(struct cxl *adapter, int slice, struct pci_dev *dev) | |||
731 | 801 | ||
732 | adapter->afu[afu->slice] = afu; | 802 | adapter->afu[afu->slice] = afu; |
733 | 803 | ||
804 | if ((rc = cxl_pci_vphb_add(afu))) | ||
805 | dev_info(&afu->dev, "Can't register vPHB\n"); | ||
806 | |||
734 | return 0; | 807 | return 0; |
735 | 808 | ||
736 | err_put2: | 809 | err_put2: |
@@ -783,8 +856,10 @@ int cxl_reset(struct cxl *adapter) | |||
783 | 856 | ||
784 | dev_info(&dev->dev, "CXL reset\n"); | 857 | dev_info(&dev->dev, "CXL reset\n"); |
785 | 858 | ||
786 | for (i = 0; i < adapter->slices; i++) | 859 | for (i = 0; i < adapter->slices; i++) { |
860 | cxl_pci_vphb_remove(adapter->afu[i]); | ||
787 | cxl_remove_afu(adapter->afu[i]); | 861 | cxl_remove_afu(adapter->afu[i]); |
862 | } | ||
788 | 863 | ||
789 | /* pcie_warm_reset requests a fundamental pci reset which includes a | 864 | /* pcie_warm_reset requests a fundamental pci reset which includes a |
790 | * PERST assert/deassert. PERST triggers a loading of the image | 865 | * PERST assert/deassert. PERST triggers a loading of the image |
@@ -857,13 +932,13 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev) | |||
857 | u8 image_state; | 932 | u8 image_state; |
858 | 933 | ||
859 | if (!(vsec = find_cxl_vsec(dev))) { | 934 | if (!(vsec = find_cxl_vsec(dev))) { |
860 | dev_err(&adapter->dev, "ABORTING: CXL VSEC not found!\n"); | 935 | dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n"); |
861 | return -ENODEV; | 936 | return -ENODEV; |
862 | } | 937 | } |
863 | 938 | ||
864 | CXL_READ_VSEC_LENGTH(dev, vsec, &vseclen); | 939 | CXL_READ_VSEC_LENGTH(dev, vsec, &vseclen); |
865 | if (vseclen < CXL_VSEC_MIN_SIZE) { | 940 | if (vseclen < CXL_VSEC_MIN_SIZE) { |
866 | pr_err("ABORTING: CXL VSEC too short\n"); | 941 | dev_err(&dev->dev, "ABORTING: CXL VSEC too short\n"); |
867 | return -EINVAL; | 942 | return -EINVAL; |
868 | } | 943 | } |
869 | 944 | ||
@@ -902,24 +977,24 @@ static int cxl_vsec_looks_ok(struct cxl *adapter, struct pci_dev *dev) | |||
902 | return -EBUSY; | 977 | return -EBUSY; |
903 | 978 | ||
904 | if (adapter->vsec_status & CXL_UNSUPPORTED_FEATURES) { | 979 | if (adapter->vsec_status & CXL_UNSUPPORTED_FEATURES) { |
905 | dev_err(&adapter->dev, "ABORTING: CXL requires unsupported features\n"); | 980 | dev_err(&dev->dev, "ABORTING: CXL requires unsupported features\n"); |
906 | return -EINVAL; | 981 | return -EINVAL; |
907 | } | 982 | } |
908 | 983 | ||
909 | if (!adapter->slices) { | 984 | if (!adapter->slices) { |
910 | /* Once we support dynamic reprogramming we can use the card if | 985 | /* Once we support dynamic reprogramming we can use the card if |
911 | * it supports loadable AFUs */ | 986 | * it supports loadable AFUs */ |
912 | dev_err(&adapter->dev, "ABORTING: Device has no AFUs\n"); | 987 | dev_err(&dev->dev, "ABORTING: Device has no AFUs\n"); |
913 | return -EINVAL; | 988 | return -EINVAL; |
914 | } | 989 | } |
915 | 990 | ||
916 | if (!adapter->afu_desc_off || !adapter->afu_desc_size) { | 991 | if (!adapter->afu_desc_off || !adapter->afu_desc_size) { |
917 | dev_err(&adapter->dev, "ABORTING: VSEC shows no AFU descriptors\n"); | 992 | dev_err(&dev->dev, "ABORTING: VSEC shows no AFU descriptors\n"); |
918 | return -EINVAL; | 993 | return -EINVAL; |
919 | } | 994 | } |
920 | 995 | ||
921 | if (adapter->ps_size > p2_size(dev) - adapter->ps_off) { | 996 | if (adapter->ps_size > p2_size(dev) - adapter->ps_off) { |
922 | dev_err(&adapter->dev, "ABORTING: Problem state size larger than " | 997 | dev_err(&dev->dev, "ABORTING: Problem state size larger than " |
923 | "available in BAR2: 0x%llx > 0x%llx\n", | 998 | "available in BAR2: 0x%llx > 0x%llx\n", |
924 | adapter->ps_size, p2_size(dev) - adapter->ps_off); | 999 | adapter->ps_size, p2_size(dev) - adapter->ps_off); |
925 | return -EINVAL; | 1000 | return -EINVAL; |
@@ -968,6 +1043,15 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev) | |||
968 | if (!(adapter = cxl_alloc_adapter(dev))) | 1043 | if (!(adapter = cxl_alloc_adapter(dev))) |
969 | return ERR_PTR(-ENOMEM); | 1044 | return ERR_PTR(-ENOMEM); |
970 | 1045 | ||
1046 | if ((rc = cxl_read_vsec(adapter, dev))) | ||
1047 | goto err1; | ||
1048 | |||
1049 | if ((rc = cxl_vsec_looks_ok(adapter, dev))) | ||
1050 | goto err1; | ||
1051 | |||
1052 | if ((rc = setup_cxl_bars(dev))) | ||
1053 | goto err1; | ||
1054 | |||
971 | if ((rc = switch_card_to_cxl(dev))) | 1055 | if ((rc = switch_card_to_cxl(dev))) |
972 | goto err1; | 1056 | goto err1; |
973 | 1057 | ||
@@ -977,12 +1061,6 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev) | |||
977 | if ((rc = dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))) | 1061 | if ((rc = dev_set_name(&adapter->dev, "card%i", adapter->adapter_num))) |
978 | goto err2; | 1062 | goto err2; |
979 | 1063 | ||
980 | if ((rc = cxl_read_vsec(adapter, dev))) | ||
981 | goto err2; | ||
982 | |||
983 | if ((rc = cxl_vsec_looks_ok(adapter, dev))) | ||
984 | goto err2; | ||
985 | |||
986 | if ((rc = cxl_update_image_control(adapter))) | 1064 | if ((rc = cxl_update_image_control(adapter))) |
987 | goto err2; | 1065 | goto err2; |
988 | 1066 | ||
@@ -1067,9 +1145,6 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1067 | if (cxl_verbose) | 1145 | if (cxl_verbose) |
1068 | dump_cxl_config_space(dev); | 1146 | dump_cxl_config_space(dev); |
1069 | 1147 | ||
1070 | if ((rc = setup_cxl_bars(dev))) | ||
1071 | return rc; | ||
1072 | |||
1073 | if ((rc = pci_enable_device(dev))) { | 1148 | if ((rc = pci_enable_device(dev))) { |
1074 | dev_err(&dev->dev, "pci_enable_device failed: %i\n", rc); | 1149 | dev_err(&dev->dev, "pci_enable_device failed: %i\n", rc); |
1075 | return rc; | 1150 | return rc; |
@@ -1078,6 +1153,7 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1078 | adapter = cxl_init_adapter(dev); | 1153 | adapter = cxl_init_adapter(dev); |
1079 | if (IS_ERR(adapter)) { | 1154 | if (IS_ERR(adapter)) { |
1080 | dev_err(&dev->dev, "cxl_init_adapter failed: %li\n", PTR_ERR(adapter)); | 1155 | dev_err(&dev->dev, "cxl_init_adapter failed: %li\n", PTR_ERR(adapter)); |
1156 | pci_disable_device(dev); | ||
1081 | return PTR_ERR(adapter); | 1157 | return PTR_ERR(adapter); |
1082 | } | 1158 | } |
1083 | 1159 | ||
@@ -1092,16 +1168,18 @@ static int cxl_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1092 | static void cxl_remove(struct pci_dev *dev) | 1168 | static void cxl_remove(struct pci_dev *dev) |
1093 | { | 1169 | { |
1094 | struct cxl *adapter = pci_get_drvdata(dev); | 1170 | struct cxl *adapter = pci_get_drvdata(dev); |
1095 | int afu; | 1171 | struct cxl_afu *afu; |
1096 | 1172 | int i; | |
1097 | dev_warn(&dev->dev, "pci remove\n"); | ||
1098 | 1173 | ||
1099 | /* | 1174 | /* |
1100 | * Lock to prevent someone grabbing a ref through the adapter list as | 1175 | * Lock to prevent someone grabbing a ref through the adapter list as |
1101 | * we are removing it | 1176 | * we are removing it |
1102 | */ | 1177 | */ |
1103 | for (afu = 0; afu < adapter->slices; afu++) | 1178 | for (i = 0; i < adapter->slices; i++) { |
1104 | cxl_remove_afu(adapter->afu[afu]); | 1179 | afu = adapter->afu[i]; |
1180 | cxl_pci_vphb_remove(afu); | ||
1181 | cxl_remove_afu(afu); | ||
1182 | } | ||
1105 | cxl_remove_adapter(adapter); | 1183 | cxl_remove_adapter(adapter); |
1106 | } | 1184 | } |
1107 | 1185 | ||
@@ -1110,4 +1188,5 @@ struct pci_driver cxl_pci_driver = { | |||
1110 | .id_table = cxl_pci_tbl, | 1188 | .id_table = cxl_pci_tbl, |
1111 | .probe = cxl_probe, | 1189 | .probe = cxl_probe, |
1112 | .remove = cxl_remove, | 1190 | .remove = cxl_remove, |
1191 | .shutdown = cxl_remove, | ||
1113 | }; | 1192 | }; |