Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018-2022 Marvell International Ltd. * * Functions for LOOP initialization, configuration, * and monitoring. */ #include <log.h> #include <malloc.h> #include <net.h> #include <linux/delay.h> #include <mach/cvmx-regs.h> #include <mach/cvmx-csr.h> #include <mach/cvmx-bootmem.h> #include <mach/octeon-model.h> #include <mach/octeon_fdt.h> #include <mach/cvmx-helper.h> #include <mach/cvmx-helper-board.h> #include <mach/cvmx-helper-cfg.h> #include <mach/cvmx-helper-fdt.h> #include <mach/cvmx-helper-gpio.h> #include <mach/cvmx-agl-defs.h> #include <mach/cvmx-bgxx-defs.h> #include <mach/cvmx-ciu-defs.h> #include <mach/cvmx-gmxx-defs.h> #include <mach/cvmx-gserx-defs.h> #include <mach/cvmx-ilk-defs.h> #include <mach/cvmx-ipd-defs.h> #include <mach/cvmx-lbk-defs.h> #include <mach/cvmx-pcsx-defs.h> #include <mach/cvmx-pcsxx-defs.h> #include <mach/cvmx-pki-defs.h> #include <mach/cvmx-pko-defs.h> #include <mach/cvmx-xcv-defs.h> #include <mach/cvmx-hwpko.h> #include <mach/cvmx-ilk.h> #include <mach/cvmx-pki.h> int __cvmx_helper_loop_enumerate(int xiface) { return OCTEON_IS_MODEL(OCTEON_CN68XX) ? 8 : (OCTEON_IS_MODEL(OCTEON_CNF71XX) ? 2 : 4); } /** * @INTERNAL * Probe a LOOP interface and determine the number of ports * connected to it. The LOOP interface should still be down * after this call. * * @param xiface Interface to probe * * @return Number of ports on the interface. Zero to disable. */ int __cvmx_helper_loop_probe(int xiface) { return __cvmx_helper_loop_enumerate(xiface); } /** * @INTERNAL * Bringup and enable a LOOP interface. After this call packet * I/O should be fully functional. This is called with IPD * enabled but PKO disabled. * * @param interface to bring up * * @return Zero on success, negative on failure */ int __cvmx_helper_loop_enable(int xiface) { cvmx_pip_prt_cfgx_t port_cfg; int num_ports, index; unsigned long offset; struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface); num_ports = __cvmx_helper_get_num_ipd_ports(xiface); /* * We need to disable length checking so packet < 64 bytes and jumbo * frames don't get errors */ for (index = 0; index < num_ports; index++) { offset = ((octeon_has_feature(OCTEON_FEATURE_PKND)) ? cvmx_helper_get_pknd(xiface, index) : cvmx_helper_get_ipd_port(xiface, index)); if (octeon_has_feature(OCTEON_FEATURE_PKI)) { cvmx_pki_endis_l2_errs(xi.node, offset, 1, 0, 0); cvmx_pki_endis_fcs_check(xi.node, offset, 0, 0); } else { port_cfg.u64 = csr_rd(CVMX_PIP_PRT_CFGX(offset)); port_cfg.s.maxerr_en = 0; port_cfg.s.minerr_en = 0; csr_wr(CVMX_PIP_PRT_CFGX(offset), port_cfg.u64); } } /* * Disable FCS stripping for loopback ports */ if (!octeon_has_feature(OCTEON_FEATURE_PKND)) { cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs; ipd_sub_port_fcs.u64 = csr_rd(CVMX_IPD_SUB_PORT_FCS); ipd_sub_port_fcs.s.port_bit2 = 0; csr_wr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64); } /* * Set PKND and BPID for loopback ports. */ if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { cvmx_pko_reg_loopback_pkind_t lp_pknd; cvmx_pko_reg_loopback_bpid_t lp_bpid; for (index = 0; index < num_ports; index++) { int pknd = cvmx_helper_get_pknd(xiface, index); int bpid = cvmx_helper_get_bpid(xiface, index); lp_pknd.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_PKIND); lp_bpid.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_BPID); if (index == 0) lp_pknd.s.num_ports = num_ports; switch (index) { case 0: lp_pknd.s.pkind0 = pknd; lp_bpid.s.bpid0 = bpid; break; case 1: lp_pknd.s.pkind1 = pknd; lp_bpid.s.bpid1 = bpid; break; case 2: lp_pknd.s.pkind2 = pknd; lp_bpid.s.bpid2 = bpid; break; case 3: lp_pknd.s.pkind3 = pknd; lp_bpid.s.bpid3 = bpid; break; case 4: lp_pknd.s.pkind4 = pknd; lp_bpid.s.bpid4 = bpid; break; case 5: lp_pknd.s.pkind5 = pknd; lp_bpid.s.bpid5 = bpid; break; case 6: lp_pknd.s.pkind6 = pknd; lp_bpid.s.bpid6 = bpid; break; case 7: lp_pknd.s.pkind7 = pknd; lp_bpid.s.bpid7 = bpid; break; } csr_wr(CVMX_PKO_REG_LOOPBACK_PKIND, lp_pknd.u64); csr_wr(CVMX_PKO_REG_LOOPBACK_BPID, lp_bpid.u64); } } else if (octeon_has_feature(OCTEON_FEATURE_BGX)) { cvmx_lbk_chx_pkind_t lbk_pkind; for (index = 0; index < num_ports; index++) { lbk_pkind.u64 = 0; lbk_pkind.s.pkind = cvmx_helper_get_pknd(xiface, index); csr_wr_node(xi.node, CVMX_LBK_CHX_PKIND(index), lbk_pkind.u64); } } return 0; } |