// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2018-2022 Marvell International Ltd. * * Functions for LOOP initialization, configuration, * and monitoring. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }