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