vlan.c (7315B)
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 * File: vlan.c 8 * Purpose: Provide low-level access to Hercules VLAN resources 9 */ 10 11 #include <soc/defs.h> 12 #if defined(BCM_HERCULES_SUPPORT) 13 #include <sal/core/boot.h> 14 #include <shared/bsl.h> 15 #include <soc/drv.h> 16 #include <soc/mem.h> 17 #include <soc/debug.h> 18 19 #include <bcm/error.h> 20 #include <bcm/vlan.h> 21 #include <bcm/port.h> 22 #include <bcm/trunk.h> 23 24 #include <bcm_int/esw/mbcm.h> 25 #include <bcm_int/esw/hercules.h> 26 27 /* 28 * Function: 29 * bcm_hercules_vlan_init 30 * Purpose: 31 * Initialize the VLAN tables with the default entry in it. 32 */ 33 34 int 35 bcm_hercules_vlan_init(int unit, bcm_vlan_data_t *vd) 36 { 37 mem_vid_entry_t ve; 38 39 if ((!SAL_BOOT_PLISIM) && (!SAL_BOOT_QUICKTURN)) { /* Way too slow! */ 40 SOC_IF_ERROR_RETURN 41 (soc_mem_clear(unit, MEM_VIDm, MEM_BLOCK_ALL, TRUE)); 42 } else { 43 LOG_CLI((BSL_META_U(unit, 44 "SIMULATION: skipped VLAN table clear " 45 "(assuming hardware did it)\n"))); 46 } 47 48 /* Initialize VLAN 1 */ 49 50 sal_memcpy(&ve, soc_mem_entry_null(unit, MEM_VIDm), sizeof (ve)); 51 52 soc_MEM_VIDm_field32_set(unit, &ve, VIDBITMAPf, 53 SOC_PBMP_WORD_GET(vd->port_bitmap, 0)); 54 55 SOC_IF_ERROR_RETURN 56 (soc_mem_write(unit, MEM_VIDm, MEM_BLOCK_ALL, vd->vlan_tag, &ve)); 57 58 return BCM_E_NONE; 59 } 60 61 /* 62 * Function: 63 * bcm_hercules_vlan_reload 64 * Purpose: 65 * Return a list of VLANs currently installed in the hardware. 66 */ 67 68 int 69 bcm_hercules_vlan_reload(int unit, vbmp_t *bmp, int *count) 70 { 71 mem_vid_entry_t ve; 72 uint32 bmval; 73 int index; 74 int blk; 75 76 (*count) = 0; 77 78 for (index = soc_mem_index_min(unit, MEM_VIDm); 79 index <= soc_mem_index_max(unit, MEM_VIDm); 80 index++) { 81 82 SOC_MEM_BLOCK_ITER(unit, MEM_VIDm, blk) { 83 84 SOC_IF_ERROR_RETURN(READ_MEM_VIDm(unit, blk, index, &ve)); 85 soc_MEM_VIDm_field_get(unit, &ve, VIDBITMAPf, &bmval); 86 87 if (bmval) { 88 SHR_BITSET(bmp->w, index); 89 (*count)++; 90 break; 91 } 92 } 93 } 94 95 return BCM_E_NONE; 96 } 97 98 /* 99 * Function: 100 * bcm_hercules_vlan_create 101 * Purpose: 102 * Create a VLAN entry in MEM_VID 103 */ 104 105 int 106 bcm_hercules_vlan_create(int unit, bcm_vlan_t vid) 107 { 108 mem_vid_entry_t ve; 109 110 /* Clear initial port bitmap */ 111 sal_memset(&ve, 0, sizeof ve); 112 113 if (vlan_info[unit].vlan_auto_stack) { 114 soc_MEM_VIDm_field32_set(unit, &ve, VIDBITMAPf, 115 SOC_PBMP_WORD_GET(PBMP_HG_ALL(unit), 0)); 116 } 117 118 SOC_IF_ERROR_RETURN(WRITE_MEM_VIDm(unit, MEM_BLOCK_ALL, vid, &ve)); 119 120 return BCM_E_NONE; 121 } 122 123 /* 124 * Function: 125 * bcm_hercules_vlan_destroy 126 * Purpose: 127 * Clear a VLAN entry in MEM_VID 128 */ 129 130 int 131 bcm_hercules_vlan_destroy(int unit, bcm_vlan_t vid) 132 { 133 mem_vid_entry_t ve; 134 int rv; 135 136 soc_mem_lock(unit, MEM_VIDm); 137 138 if ((rv = READ_MEM_VIDm(unit, MEM_BLOCK_ANY, vid, &ve)) >= 0) { 139 soc_MEM_VIDm_field32_set(unit, &ve, VIDBITMAPf, 0); 140 141 rv = WRITE_MEM_VIDm(unit, MEM_BLOCK_ALL, vid, &ve); 142 } 143 144 soc_mem_unlock(unit, MEM_VIDm); 145 146 return rv; 147 } 148 149 /* 150 * Function: 151 * bcm_hercules_vlan_port_update 152 * Purpose: 153 * Add/remove ports to the VLAN bitmap in a MEM_VID entry. 154 * Notes: 155 * Each port has its own forwarding port mask for all VLANs. 156 * If a port is not a member of a VLAN, the corresponding 157 * forwarding port mask is set to zero. This way the table 158 * also acts as an ingress VLAN filter. 159 */ 160 161 STATIC int 162 bcm_hercules_vlan_port_update(int unit, bcm_vlan_t vid, pbmp_t pbmp, int add) 163 { 164 mem_vid_entry_t ve[SOC_MAX_NUM_BLKS]; 165 int port, blk; 166 uint32 bmval = 0; 167 int rv; 168 169 soc_mem_lock(unit, MEM_VIDm); 170 171 /* Read VLAN entries for all blocks */ 172 SOC_MEM_BLOCK_ITER(unit, MEM_VIDm, blk) { 173 174 rv = READ_MEM_VIDm(unit, blk, vid, &ve[blk]); 175 176 if (SOC_FAILURE(rv)) { 177 soc_mem_unlock(unit, MEM_VIDm); 178 return rv; 179 } 180 181 if (bmval == 0) { 182 /* Pick up ports from existing VLAN member */ 183 soc_MEM_VIDm_field_get(unit, &ve[blk], VIDBITMAPf, &bmval); 184 } 185 } 186 187 if (add) { 188 bmval |= SOC_PBMP_WORD_GET(pbmp, 0); 189 } else { 190 bmval &= ~SOC_PBMP_WORD_GET(pbmp, 0); 191 } 192 193 /* Write non-zero entries for VLAN members only */ 194 SOC_MEM_BLOCK_ITER(unit, MEM_VIDm, blk) { 195 port = SOC_BLOCK_PORT(unit, blk); 196 soc_MEM_VIDm_field32_set(unit, &ve[blk], VIDBITMAPf, 197 (bmval & (1 << port)) ? bmval : 0); 198 rv = WRITE_MEM_VIDm(unit, blk, vid, &ve[blk]); 199 if (SOC_FAILURE(rv)){ 200 soc_mem_unlock(unit, MEM_VIDm); 201 return (rv); 202 } 203 } 204 205 soc_mem_unlock(unit, MEM_VIDm); 206 207 return BCM_E_NONE; 208 } 209 210 /* 211 * Function: 212 * bcm_hercules_vlan_port_add 213 * Purpose: 214 * Add ports to the VLAN bitmap in a MEM_VID entry. 215 */ 216 217 int 218 bcm_hercules_vlan_port_add(int unit, bcm_vlan_t vid, pbmp_t pbmp, pbmp_t ubmp, 219 pbmp_t ing_pbmp) 220 { 221 BCM_PBMP_OR(pbmp, ing_pbmp); 222 223 return bcm_hercules_vlan_port_update(unit, vid, pbmp, 1); 224 } 225 226 /* 227 * Function: 228 * bcm_hercules_vlan_port_remove 229 * Purpose: 230 * Remove ports from the VLAN bitmap in a MEM_VID entry. 231 */ 232 233 int 234 bcm_hercules_vlan_port_remove(int unit, bcm_vlan_t vid, pbmp_t pbmp, 235 pbmp_t ubmp, pbmp_t ing_pbmp) 236 { 237 return bcm_hercules_vlan_port_update(unit, vid, pbmp, 0); 238 } 239 240 /* 241 * Function: 242 * bcm_hercules_vlan_port_get 243 * Purpose: 244 * Read the port bitmap from a MEM_VID entry. 245 */ 246 247 int 248 bcm_hercules_vlan_port_get(int unit, bcm_vlan_t vid, pbmp_t *pbmp, 249 pbmp_t *ubmp, pbmp_t *ing_pbmp) 250 { 251 mem_vid_entry_t ve; 252 int blk; 253 uint32 bmval = 0; 254 int rv; 255 256 soc_mem_lock(unit, MEM_VIDm); 257 258 SOC_MEM_BLOCK_ITER(unit, MEM_VIDm, blk) { 259 260 rv = READ_MEM_VIDm(unit, blk, vid, &ve); 261 262 if (SOC_FAILURE(rv)) { 263 soc_mem_unlock(unit, MEM_VIDm); 264 return rv; 265 } 266 267 bmval = soc_MEM_VIDm_field32_get(unit, &ve, VIDBITMAPf); 268 if (bmval) { 269 break; 270 } 271 } 272 273 if (pbmp != NULL) { 274 SOC_PBMP_CLEAR(*pbmp); 275 SOC_PBMP_WORD_SET(*pbmp, 0, bmval); 276 } 277 278 if (ubmp != NULL) { 279 SOC_PBMP_CLEAR(*ubmp); 280 } 281 282 if (ing_pbmp != NULL) { 283 SOC_PBMP_CLEAR(*ing_pbmp); 284 SOC_PBMP_WORD_SET(*ing_pbmp, 0, bmval); 285 } 286 287 soc_mem_unlock(unit, MEM_VIDm); 288 289 return BCM_E_NONE; 290 } 291 292 /* 293 * Function: 294 * bcm_hercules_vlan_stg_get 295 * Purpose: 296 * Stub out STG on Hercules 297 */ 298 299 int 300 bcm_hercules_vlan_stg_get(int unit, bcm_vlan_t vid, bcm_stg_t *stg_ptr) 301 { 302 COMPILER_REFERENCE(unit); 303 COMPILER_REFERENCE(vid); 304 305 *stg_ptr = 1; /* Only one "STG" on Hercules */ 306 307 return BCM_E_NONE; 308 } 309 310 /* 311 * Function: 312 * bcm_hercules_vlan_stg_set 313 * Purpose: 314 * Stub out STG on Hercules 315 */ 316 317 int 318 bcm_hercules_vlan_stg_set(int unit, bcm_vlan_t vid, bcm_stg_t stg) 319 { 320 COMPILER_REFERENCE(unit); 321 COMPILER_REFERENCE(vid); 322 323 /* Only one "STG" on Hercules */ 324 325 return (stg == 1) ? BCM_E_NONE : BCM_E_BADID; 326 } 327 #else /* BCM_HERCULES_SUPPORT */ 328 int _hercules_vlan_not_empty; 329 #endif /* BCM_HERCULES_SUPPORT */