macsecphy.c (12583B)
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 * StrataSwitch MACSEC PHY control 8 * MACSEC PHY initialization 9 */ 10 11 12 #include <shared/bsl.h> 13 14 #include <soc/drv.h> 15 #include <soc/phy/phyctrl.h> 16 #include <soc/phy/drv.h> 17 #include <soc/debug.h> 18 19 #ifdef INCLUDE_MACSEC 20 #include <bmacsec.h> 21 #ifdef BCM_SWITCHMACSEC_SUPPORT 22 #include <dummyphy.h> 23 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 24 #if defined(INCLUDE_PHY_8729) 25 #include <phy8729.h> 26 #endif 27 #include <soc/macsecphy.h> 28 29 30 /* speed_get register */ 31 typedef int (*bmacsec_speed_get_f) (void * ext_port_handle, int * speed); 32 33 extern void 34 _bmacsec_register_speed_get(int port, bmacsec_speed_get_f f, void *pc); 35 36 37 38 int soc_macsecphy_speed_get(void * ext_port_handle, int * speed) { 39 40 int rv; 41 phy_ctrl_t *pc = (phy_ctrl_t *) ext_port_handle; 42 43 if (speed == NULL) { 44 return -1; 45 } 46 47 *speed = 0; 48 49 if (pc) { 50 rv = PHYCTRL_SPEED_GET(pc, pc->unit, pc->port, speed); 51 if (rv != SOC_E_NONE) { 52 *speed = 0; 53 return -1; 54 } 55 } 56 57 return 0; 58 } 59 60 61 /* 62 * Function: 63 * soc_macsecphy_init 64 * Purpose: 65 * Initializes the MACSEC phy port. 66 * Parameters: 67 * unit - SOC Unit #. 68 * port - Port number. 69 * pc - Phy control structure 70 * Returns: 71 * SOC_E_XXX 72 */ 73 int 74 soc_macsecphy_init(int unit, soc_port_t port, phy_ctrl_t *pc, 75 bmacsec_core_t core_type, bmacsec_dev_io_f iofn) 76 { 77 int /* ii, */ p, rv; 78 int macsec_enable = 0; 79 80 p = SOC_MACSEC_PORTID(unit, port); 81 /* Destroy the port if it were created before. */ 82 (void)bmacsec_port_destroy(p); 83 84 macsec_enable = soc_property_port_get(unit, port, spn_MACSEC_ENABLE, 0); 85 pc->macsec_enable = macsec_enable; 86 87 if (macsec_enable) { 88 /* Create MACSEC Port */ 89 rv = bmacsec_port_create(p, core_type, pc->macsec_dev_addr, 90 pc->macsec_dev_port, iofn); 91 if (rv != BMACSEC_E_NONE) { 92 LOG_WARN(BSL_LS_SOC_COMMON, 93 (BSL_META_U(unit, 94 "soc_macsecphy_init: " 95 "MACSEC port create failed for u=%d p=%d rv = %d\n"), 96 unit, port, rv)); 97 return SOC_E_FAIL; 98 } 99 100 /* register speed_get */ 101 _bmacsec_register_speed_get(p, soc_macsecphy_speed_get, (void *) pc); 102 } 103 return SOC_E_NONE; 104 } 105 106 int 107 soc_macsecphy_miim_read(soc_macsec_dev_addr_t dev_addr, 108 uint32 phy_reg_addr, uint16 *data) 109 { 110 int unit, phy_id, clause45; 111 int rv = SOC_E_NONE; 112 #ifdef BCM_SWITCHMACSEC_SUPPORT 113 int nophy_macsec = 0; 114 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 115 116 /* 117 * Decode dev_addr into phyid and unit. 118 */ 119 unit = SOC_MACSECPHY_ADDR2UNIT(dev_addr); 120 phy_id = SOC_MACSECPHY_ADDR2MDIO(dev_addr); 121 #ifdef BCM_SWITCHMACSEC_SUPPORT 122 nophy_macsec = SOC_MACSECPHY_ADDR_IS_FLAG_NOPHY(dev_addr);; 123 clause45 = SOC_MACSECPHY_ADDR_IS_FLAG_CLAUSE45(dev_addr); 124 #else /* BCM_SWITCHMACSEC_SUPPORT */ 125 clause45 = SOC_MACSECPHY_ADDR_IS_CLAUSE45(dev_addr); 126 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 127 128 #ifdef BCM_ESW_SUPPORT 129 if (SOC_IS_ESW(unit)) { 130 if (clause45) { 131 rv = soc_esw_miimc45_read(unit, phy_id, 132 phy_reg_addr, data); 133 } else { 134 rv = soc_miim_read(unit, phy_id, phy_reg_addr, data); 135 } 136 } 137 #endif /* BCM_ESW_SUPPORT */ 138 139 return (rv == SOC_E_NONE) ? 0 : -1; 140 } 141 142 int 143 soc_macsecphy_miim_write(soc_macsec_dev_addr_t dev_addr, 144 uint32 phy_reg_addr, uint16 data) 145 { 146 int unit, phy_id, clause45; 147 int rv = SOC_E_NONE; 148 #ifdef BCM_SWITCHMACSEC_SUPPORT 149 int nophy_macsec = 0; 150 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 151 152 /* 153 * Decode dev_addr into phyid and unit. 154 */ 155 unit = SOC_MACSECPHY_ADDR2UNIT(dev_addr); 156 phy_id = SOC_MACSECPHY_ADDR2MDIO(dev_addr); 157 158 #ifdef BCM_SWITCHMACSEC_SUPPORT 159 nophy_macsec = SOC_MACSECPHY_ADDR_IS_FLAG_NOPHY(dev_addr);; 160 clause45 = SOC_MACSECPHY_ADDR_IS_FLAG_CLAUSE45(dev_addr); 161 #else /* BCM_SWITCHMACSEC_SUPPORT */ 162 clause45 = SOC_MACSECPHY_ADDR_IS_CLAUSE45(dev_addr); 163 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 164 165 #ifdef BCM_ESW_SUPPORT 166 if (SOC_IS_ESW(unit)) { 167 if (clause45) { 168 rv = soc_esw_miimc45_write(unit, phy_id, 169 phy_reg_addr, data); 170 } else { 171 rv = soc_miim_write(unit, phy_id, phy_reg_addr, data); 172 } 173 } 174 #endif /* BCM_ESW_SUPPORT */ 175 176 return (rv == SOC_E_NONE) ? 0 : -1; 177 } 178 179 180 #ifdef BCM_SWITCHMACSEC_SUPPORT 181 int 182 soc_switchmacsec_init(int unit, soc_port_t port) 183 { 184 int rv = SOC_E_NONE; 185 int addr_flags = 0, macsec_devid = -1; 186 int mmi_mdio_addr, port_index, macsec_enable, macsec_dev_port_cnt; 187 phy_ctrl_t *pc; 188 bmacsec_core_t macsec_core = BMACSEC_CORE_UNKNOWN; 189 bmacsec_dev_io_f macsec_mmi_io = NULL; 190 bmacsec_mactype_t macsec_mac = BMACSEC_MAC_CORE_UNKNOWN; 191 bmacsec_dev_addr_t macsec_dev_addr, macsec_dev_idx; 192 193 LOG_INFO(BSL_LS_SOC_PHY, 194 (BSL_META_U(unit, 195 "%s: u=%d port=%d\n"), 196 FUNCTION_NAME(), unit, port)); 197 198 SOC_NOPHY_MACSEC_DEVID_GET(unit, port, macsec_devid); 199 if (macsec_devid == -1) { 200 return SOC_E_NONE; 201 } 202 203 pc = EXT_PHY_SW_STATE(unit, port); 204 if (pc == NULL) { 205 pc = INT_PHY_SW_STATE(unit, port); 206 if (pc == NULL) { 207 LOG_ERROR(BSL_LS_SOC_COMMON, 208 (BSL_META_U(unit, 209 "no PHY driver attached on u=%d p=%d\n"), 210 unit, port)); 211 return SOC_E_CONFIG; 212 } 213 } 214 215 mmi_mdio_addr = soc_property_port_get(unit, port, spn_MACSEC_DEV_ADDR, -1); 216 if (mmi_mdio_addr == -1) { 217 LOG_WARN(BSL_LS_SOC_COMMON, 218 (BSL_META_U(unit, 219 "MACSEC_DEV_ADDR property not configured for u=%d p=%d\n"), 220 unit, port)); 221 return SOC_E_CONFIG; 222 } 223 224 port_index = soc_property_port_get(unit, port, spn_MACSEC_PORT_INDEX, -1); 225 if (port_index == -1) { 226 LOG_WARN(BSL_LS_SOC_COMMON, 227 (BSL_META_U(unit, 228 "MACSEC_PORT_INDEX property not configured for u=%d p=%d\n"), 229 unit, port)); 230 return SOC_E_CONFIG; 231 } 232 233 macsec_enable = soc_property_port_get(unit, port, spn_MACSEC_ENABLE, 0); 234 235 pc->macsec_dev_addr = mmi_mdio_addr; 236 pc->macsec_dev_port = port_index; 237 pc->macsec_enable = macsec_enable; 238 239 addr_flags = SOC_MACSECPHY_MDIO_FLAGS_NOPHY; 240 macsec_dev_idx = SOC_MACSECPHY_MDIO_ADDR(unit, macsec_devid, addr_flags); 241 macsec_dev_addr = SOC_MACSECPHY_MDIO_ADDR(unit, mmi_mdio_addr, addr_flags); 242 243 /* core type and LMI/MMI io function assignment : 244 * - The core type, MAC type, macsec_dev_port_cnt and LMI/MMI io-function in current SDK is force assigned. 245 */ 246 SOC_NOPHY_MACSEC_CORE_GET(unit, macsec_core, macsec_dev_port_cnt); 247 SOC_NOPHY_MACSEC_MAC_GET(unit, macsec_mac); 248 SOC_NOPHY_MACSEC_MMI_GET(unit, macsec_mmi_io); 249 250 /* core type and LMI/MMI io function assignment : 251 * - The core type and LMI/MMI io-function in current SDK is force assigned. 252 */ 253 /* 254 * COVERITY 255 * 256 * This default is unreachable in some conditional builds. 257 * (Currently the SwitchMACSEC(MACSEC-in-Switch) is supported in ROBO 258 * switch only) 259 * 260 * To keep this design for the supporting ability while different chip 261 * Arch.(like ESW) in future has SwitchMACSEC chip design. 262 */ 263 /* coverity[dead_error_begin] */ 264 if ((macsec_core == BMACSEC_CORE_UNKNOWN) || (macsec_dev_port_cnt <= 0) || \ 265 (macsec_mac == BMACSEC_MAC_CORE_UNKNOWN) || \ 266 (macsec_mmi_io == NULL)) { 267 LOG_WARN(BSL_LS_SOC_COMMON, 268 (BSL_META_U(unit, 269 "MACSEC core, MAC or LMI iofu is not predefined!\n"))); 270 } 271 272 /* call to bmacsec_dummyphy_phy_mac_addr_set() for assigning those macsec 273 * related address and id for MDIO access. 274 * Flow : 275 * 1. assigning address mapping table between PHY/MAC/port. 276 * 2. attaching MAC driver. (in UNIMAC/BIGMAC/XMAC) 277 */ 278 rv = bmacsec_dummyphy_mac_addr_set(macsec_dev_idx, macsec_dev_addr, 279 port_index, macsec_dev_port_cnt, macsec_mmi_io, macsec_mac); 280 if(rv != BMACSEC_E_NONE) { 281 LOG_WARN(BSL_LS_SOC_COMMON, 282 (BSL_META_U(unit, 283 "bmacsec_phy_mac_addr_set returned error for u=%d p=%d\n"), 284 unit, port)); 285 return SOC_E_INTERNAL; 286 } 287 288 if (macsec_enable) { 289 /* init MACSEC's Line/Switch MAC */ 290 rv = bmacsec_dummyphy_mac_init(macsec_dev_idx, macsec_enable); 291 if(rv != BMACSEC_E_NONE) { 292 LOG_ERROR(BSL_LS_SOC_COMMON, 293 (BSL_META_U(unit, 294 "failed on init MACSEC's MAC for u=%d p=%d\n"), 295 unit, port)); 296 return SOC_E_INTERNAL; 297 } 298 } 299 300 /* set MACSEC bypass control */ 301 rv = soc_macsecphy_dev_control_set(unit, port, 302 SOC_MACSECPHY_DEV_CONTROL_BYPASS, (macsec_enable ? FALSE : TRUE)); 303 if (!SOC_SUCCESS(rv)) { 304 LOG_ERROR(BSL_LS_SOC_COMMON, 305 (BSL_META_U(unit, 306 "failed on setting MACSEC Bypass for u=%d p=%d\n"), 307 unit, port)); 308 return SOC_E_INTERNAL; 309 } 310 311 /* performing common macsecphy init process */ 312 rv = soc_macsecphy_init(unit, port, pc, macsec_core, macsec_mmi_io); 313 314 if (!SOC_SUCCESS(rv)) { 315 LOG_ERROR(BSL_LS_SOC_COMMON, 316 (BSL_META_U(unit, 317 "soc_switchmacsec_init: MACSEC init for" 318 " u=%d p=%d FAILED\n"), unit, port)); 319 } else { 320 LOG_INFO(BSL_LS_SOC_PHY, 321 (BSL_META_U(unit, 322 "soc_switchmacsec_init: MACSEC init for" 323 " u=%d p=%d SUCCESS\n"), unit, port)); 324 } 325 return rv; 326 327 } 328 329 #endif /* BCM_SWITCHMACSEC_SUPPORT */ 330 331 /* The routine for control set/get is for the setting items which are unable 332 * to be accessed in MACSEC's internal registers. Normally, this is for the 333 * control on whole MACSEC unit like bypass, power-down or reset etc. 334 * 335 * This request normally is for MACSEC-in-SWITCH solution 336 * (i.e. NOPHY_MACSEC). And the reasons is MACSEC-in-PHY solution for the 337 * purpose to control whole MACSEC unit can through PHY expanded regsiter. 338 * 339 * In current existed SDK solution(MACSEC-in-PHY solution), such contorl 340 * set/get all implemented in each independent PHY driver already. 341 */ 342 int 343 soc_macsecphy_dev_control_set(int unit, soc_port_t port, int type, uint32 value) 344 { 345 int rv = SOC_E_NONE; 346 347 switch (type) { 348 case SOC_MACSECPHY_DEV_CONTROL_BYPASS: 349 350 rv = SOC_E_UNAVAIL; 351 break; 352 case SOC_MACSECPHY_DEV_CONTROL_POWERDOWN: 353 case SOC_MACSECPHY_DEV_CONTROL_RESET: 354 rv = SOC_E_UNAVAIL; 355 break; 356 default: 357 rv = SOC_E_PARAM; 358 } 359 360 return rv; 361 } 362 363 int 364 soc_macsecphy_dev_control_get(int unit, soc_port_t port, int type, uint32 *value) 365 { 366 int rv = SOC_E_NONE; 367 368 switch (type) { 369 case SOC_MACSECPHY_DEV_CONTROL_BYPASS: 370 371 rv = SOC_E_UNAVAIL; 372 break; 373 case SOC_MACSECPHY_DEV_CONTROL_POWERDOWN: 374 case SOC_MACSECPHY_DEV_CONTROL_RESET: 375 rv = SOC_E_UNAVAIL; 376 break; 377 default: 378 rv = SOC_E_PARAM; 379 } 380 381 return rv; 382 } 383 384 /* Function : soc_macsecphy_dev_info_get() : 385 * - for the purpose to report the MACSEC related information. 386 * 387 * Parameters : 388 * - port : the switch port ID. 389 * - type : information type 390 * - value : (OUTPUT) value for this information type 391 */ 392 int 393 soc_macsecphy_dev_info_get(int unit, soc_port_t port, int type, uint32 *value) 394 { 395 int rv = SOC_E_NONE; 396 397 switch (type) { 398 case SOC_MACSECPHY_DEV_INFO_SWITCHMACSEC_ATTACHED: 399 *value = FALSE; 400 401 402 break; 403 default: 404 rv = SOC_E_PARAM; 405 } 406 407 return rv; 408 } 409 410 #else /* INCLUDE_MACSEC */ 411 412 int 413 soc_macsecphy_init(int unit, soc_port_t port, void *pc) 414 { 415 return SOC_E_NONE; 416 } 417 #endif /* INCLUDE_MACSEC */ 418