linkscan.c (10328B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * tr60 - Linkscan MDIO 8 * Loop reading the MII registers ID0 and ID1(RO registers), verifying 9 * they never change 10 */ 11 12 #include <shared/bsl.h> 13 14 #include <sal/types.h> 15 #include <sal/core/boot.h> 16 #include <sal/appl/sal.h> 17 #include <appl/diag/system.h> 18 #include <appl/diag/parse.h> 19 #include <shared/bsl.h> 20 #include <soc/types.h> 21 #include <soc/debug.h> 22 23 #include <soc/enet.h> 24 #include <soc/counter.h> 25 #include <soc/register.h> 26 #include <soc/memory.h> 27 #include <soc/phyctrl.h> 28 #include <soc/phyreg.h> 29 #include <soc/phy.h> 30 #if defined(PORTMOD_SUPPORT) 31 #include <soc/portmod/portmod.h> 32 #endif 33 34 #include <bcm/error.h> 35 #include <bcm/port.h> 36 #include <bcm/vlan.h> 37 #include <bcm/link.h> 38 #include <appl/test/loopback.h> 39 40 #include "testlist.h" 41 #include <appl/diag/system.h> 42 #include <appl/diag/progress.h> 43 44 #if defined(BCM_PETRA_SUPPORT) 45 #include <soc/dpp/port_sw_db.h> 46 #endif 47 48 #ifdef PORTMOD_SUPPORT 49 #include <soc/portmod/portmod.h> 50 #include <soc/portmod/portmod_common.h> 51 #endif /* PORTMOD_SUPPORT */ 52 #include <soc/esw/portctrl.h> 53 54 #if defined (BCM_ESW_SUPPORT) || defined (BCM_PETRA_SUPPORT) || defined(BCM_DFE_SUPPORT) || defined(BCM_DNX_SUPPORT) || defined(BCM_DNXF_SUPPORT) 55 56 typedef struct linkscan_work_s{ 57 int ls_scan[SOC_MAX_NUM_PORTS]; 58 uint32 ls_id0[SOC_MAX_NUM_PORTS]; 59 uint32 ls_id1[SOC_MAX_NUM_PORTS]; 60 uint32 ls_flags[SOC_MAX_NUM_PORTS]; /* Internal phy? */ 61 pbmp_t ls_ports; 62 int ls_reads; /* # reads to perform */ 63 } linkscan_work_t; 64 65 static linkscan_work_t *ls_work[SOC_MAX_NUM_DEVICES]; 66 67 int 68 ls_test(int u, args_t *args, void *pa) 69 { 70 linkscan_work_t *ls = (linkscan_work_t *)pa; 71 soc_port_t p; 72 int rv, r; 73 uint32 id0, id1; 74 75 progress_init(ls->ls_reads, 1, 0); 76 /* 77 * Loop reading the MII registers ID0 and ID1, verifying they never change 78 */ 79 80 for (r = 0; r < ls->ls_reads; ) { 81 PBMP_ITER(ls->ls_ports, p) { 82 rv = bcm_port_phy_get(u, p, ls->ls_flags[p], 83 BCM_PORT_PHY_REG_INDIRECT_ADDR(0, 0, MII_PHY_ID0_REG), 84 &id0); 85 if (rv < 0) { 86 test_error(u, "Failed to read port %d Phy-id %d ID0: %s\n", 87 p, PORT_TO_PHY_ADDR(u, p), bcm_errmsg(rv)); 88 } 89 rv = bcm_port_phy_get(u, p, ls->ls_flags[p], 90 BCM_PORT_PHY_REG_INDIRECT_ADDR(0, 0, MII_PHY_ID1_REG), 91 &id1); 92 if (rv < 0) { 93 test_error(u, "Failed to read port %d Phy-id %d ID1: %s\n", 94 p, PORT_TO_PHY_ADDR(u, p), bcm_errmsg(rv)); 95 } 96 if ((id0 != ls->ls_id0[p]) || (id1 != ls->ls_id1[p])) { 97 test_error(u, 98 "Register Compare error: port %s: " 99 "Expected phy id 0x%04x 0x%04x, " 100 "Read phy id 0x%04x 0x%04x", 101 SOC_PORT_NAME(u, p), 102 ls->ls_id0[p], ls->ls_id1[p], id0, id1); 103 } 104 r += 2; 105 progress_report(2); 106 } 107 } 108 progress_done(); 109 return(0); 110 } 111 112 int 113 ls_test_init(int u, args_t *args, void **pa) 114 { 115 soc_port_t p; 116 int rv; 117 linkscan_work_t *ls; 118 parse_table_t pt; 119 pbmp_t pbmp; 120 #if defined(PORTMOD_SUPPORT) 121 phymod_core_access_t core_access_arr[MAX_NUM_CORES]; 122 int max_buf = MAX_NUM_CORES; 123 int nof_cores, is_most_ext; 124 #endif 125 126 if (ls_work[u] == NULL) { 127 ls_work[u] = sal_alloc(sizeof(linkscan_work_t), "ls_test"); 128 if (ls_work[u] == NULL) { 129 test_error(u, "ERROR: cannot allocate memory\n"); 130 return -1; 131 } 132 sal_memset(ls_work[u], 0, sizeof(linkscan_work_t)); 133 } 134 ls = ls_work[u]; 135 136 parse_table_init(u, &pt); 137 parse_table_add(&pt, "Readcount", PQ_INT, (void *)100000, &ls->ls_reads, 138 NULL); 139 140 if (parse_arg_eq(args, &pt) < 0 || ARG_CNT(args) != 0) { 141 test_error(u, "%s: Invalid Option: %s\n", ARG_CMD(args), 142 ARG_CUR(args) ? ARG_CUR(args) : "*"); 143 } 144 parse_arg_eq_done(&pt); 145 146 /* 147 * Save old state, and enable H/W link scanning on FE ports. 148 */ 149 150 BCM_PBMP_CLEAR(pbmp); 151 152 BCM_PBMP_ASSIGN(pbmp, PBMP_FE_ALL(u)); /* Handle Strata 24+2 */ 153 154 if (BCM_PBMP_IS_NULL(pbmp)) { 155 BCM_PBMP_ASSIGN(pbmp, PBMP_GE_ALL(u)); 156 } 157 158 if (BCM_PBMP_IS_NULL(pbmp)) { 159 BCM_PBMP_ASSIGN(pbmp, PBMP_XE_ALL(u)); 160 } 161 162 #ifdef BCM_XGS3_SWITCH_SUPPORT 163 if (SOC_IS_XGS3_SWITCH(u)) { 164 BCM_PBMP_ASSIGN(pbmp, PBMP_PORT_ALL(u)); 165 } 166 #endif 167 168 #if defined(BCM_PETRA_SUPPORT) 169 if (SOC_IS_ARAD(u)) { 170 uint32 flags; 171 pbmp_t stat_ifs; 172 173 BCM_PBMP_CLEAR(stat_ifs); 174 PBMP_ITER(pbmp, p){ 175 rv = soc_port_sw_db_flags_get(u, p, &flags); 176 if (0 > rv) { 177 test_error(u, "soc_port_sw_db_flags_get: port %d: %s\n", 178 p, bcm_errmsg(rv)); 179 sal_free(ls); 180 ls_work[u] = NULL; 181 return(-1); 182 } 183 if(SOC_PORT_IS_STAT_INTERFACE(flags)) { 184 BCM_PBMP_PORT_ADD(stat_ifs, p); 185 } 186 } 187 BCM_PBMP_REMOVE(pbmp, stat_ifs); 188 } 189 #endif 190 191 #if defined(BCM_DFE_SUPPORT) || defined(BCM_PETRA_SUPPORT) 192 if (SOC_IS_DFE(u) || SOC_IS_ARAD(u)) { 193 BCM_PBMP_OR(pbmp, PBMP_SFI_ALL(u)); 194 } 195 #endif 196 197 if (BCM_PBMP_IS_NULL(pbmp)) { 198 test_error(u, "Test not available on %s\n", soc_dev_name(u)); 199 sal_free(ls); 200 ls_work[u] = NULL; 201 return(-1); 202 } 203 204 if (bsl_check(bslLayerAppl, bslSourceTests, bslSeverityNormal, u)) { 205 char s[FORMAT_PBMP_MAX]; 206 (void)format_pbmp(u, s, sizeof(s), pbmp); 207 LOG_INFO(BSL_LS_APPL_TESTS, 208 (BSL_META_U(u, 209 "Running on ports: %s\n"), s)); 210 } 211 212 PBMP_ITER(pbmp, p) { 213 if (0 > (rv = bcm_port_linkscan_get(u, p, &ls->ls_scan[p]))) { 214 test_error(u, "bcm_port_linkscan_get: port %d: %s\n", 215 p, bcm_errmsg(rv)); 216 sal_free(ls); 217 ls_work[u] = NULL; 218 return(-1); 219 } 220 } 221 222 /* At this point, can restore from it */ 223 224 BCM_PBMP_CLEAR(ls->ls_ports); 225 *pa = (void *)ls; 226 227 PBMP_ITER(pbmp, p) { 228 /* Internal or external phy? */ 229 if (!SOC_USE_PORTCTRL(u)) { 230 ls->ls_flags[p] = 231 (PORT_TO_PHY_ADDR(u, p) == PORT_TO_PHY_ADDR_INT(u, p)) ? 232 SOC_PHY_INTERNAL : 0; 233 } 234 #if defined(PORTMOD_SUPPORT) 235 else { 236 rv = portmod_port_core_access_get(u, p, 0, max_buf, 237 core_access_arr, &nof_cores, &is_most_ext); 238 239 if (rv < 0) { 240 test_error(u, "portmod_port_chain_core_access_get port %d: %s\n", 241 p, bcm_errmsg(rv)); 242 sal_free(ls); 243 ls_work[u] = NULL; 244 return(-1); 245 } 246 ls->ls_flags[p] = 247 (is_most_ext == 1) ? 248 SOC_PHY_INTERNAL : 0; 249 } 250 #endif 251 if (0 > (rv = bcm_port_linkscan_set(u, p, BCM_LINKSCAN_MODE_HW))) { 252 test_error(u, "bcm_port_linkscan_set: port %d: %s\n", 253 p, bcm_errmsg(rv)); 254 sal_free(ls); 255 ls_work[u] = NULL; 256 return(-1); 257 } 258 rv = bcm_port_phy_get(u, p, ls->ls_flags[p], 259 BCM_PORT_PHY_REG_INDIRECT_ADDR(0, 0, MII_PHY_ID0_REG), 260 &ls->ls_id0[p]); 261 if (rv < 0) { 262 if (rv == SOC_E_UNAVAIL) { 263 /* Skip this port, PHY read unsupported. NULL PHY? */ 264 /* Restore linkscan state here */ 265 if (0 > (rv = bcm_port_linkscan_set(u, p, ls->ls_scan[p]))) { 266 test_error(u, "bcm_port_linkscan_set: port %d: %s\n", 267 p, bcm_errmsg(rv)); 268 sal_free(ls); 269 ls_work[u] = NULL; 270 return(-1); 271 } 272 LOG_WARN(BSL_LS_APPL_TESTS, 273 (BSL_META_U(u, 274 "Port %d skipped due to unsupported PHY reads.\n"), p)); 275 continue; 276 } else { 277 test_error(u, "Failed to read port %d Phy-addr %d ID0: %s\n", 278 p, PORT_TO_PHY_ADDR(u, p), bcm_errmsg(rv)); 279 sal_free(ls); 280 ls_work[u] = NULL; 281 return(-1); 282 } 283 } 284 rv = bcm_port_phy_get(u, p, ls->ls_flags[p], 285 BCM_PORT_PHY_REG_INDIRECT_ADDR(0, 0, MII_PHY_ID1_REG), 286 &ls->ls_id1[p]); 287 if (rv < 0) { 288 test_error(u, "Failed to read port %d Phy-addr %d ID1: %s\n", 289 p, PORT_TO_PHY_ADDR(u, p), bcm_errmsg(rv)); 290 sal_free(ls); 291 ls_work[u] = NULL; 292 return(-1); 293 } 294 LOG_INFO(BSL_LS_APPL_TESTS, 295 (BSL_META_U(u, 296 "unit %d port %s has phy id 0x%04x 0x%04x\n"), 297 u, SOC_PORT_NAME(u, p), ls->ls_id0[p], ls->ls_id1[p])); 298 BCM_PBMP_PORT_ADD(ls->ls_ports, p); 299 } 300 301 if (BCM_PBMP_IS_NULL(ls->ls_ports)) { 302 test_error(u, "No valid ports left to test!\n"); 303 sal_free(ls); 304 ls_work[u] = NULL; 305 return(-1); 306 } 307 308 return(0); 309 } 310 311 int 312 ls_test_done(int u, void *pa) 313 { 314 soc_port_t p; 315 int rv; 316 linkscan_work_t *ls = (linkscan_work_t *)pa; 317 318 if (NULL == ls) { 319 return(0); 320 } 321 322 PBMP_ITER(ls->ls_ports, p) { 323 if (0 > (rv = bcm_port_linkscan_set(u, p, ls->ls_scan[p]))) { 324 test_error(u, "bcm_port_linkscan_set: port %d: %s\n", 325 p, bcm_errmsg(rv)); 326 sal_free(ls); 327 ls_work[u] = NULL; 328 return(-1); 329 } 330 } 331 sal_free(ls); 332 ls_work[u] = NULL; 333 return(0); 334 } 335 #endif /* BCM_ESW_SUPPORT */