socend.c (43947B)
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: socend.c 8 * Purpose: Defines SOC device END driver for VxWorks. 9 * 10 * 11 * If VLAN tag in tx packet, extract PRI and map to COS 12 * Provide default COS for untagged packets 13 * Determine IP packet snooping really required; remove if not 14 * Determine reasonable "reason filter" for RX; 15 * and/or provide filter callback on RX. 16 */ 17 18 19 #include <shared/bsl.h> 20 21 #include <sys/types.h> 22 #include <sal/core/libc.h> 23 #include <sal/appl/sal.h> 24 25 #include <end.h> 26 #include <endLib.h> 27 #include <netLib.h> 28 #include <netBufLib.h> 29 #include <etherMultiLib.h> 30 31 #include <appl/diag/system.h> 32 #if defined(BROADCOM_DEBUG) 33 # include <appl/diag/decode.h> 34 #endif /* BROADCOM_DEBUG */ 35 36 #include <soc/enet.h> 37 #include <soc/util.h> 38 39 #include <bcm/error.h> 40 #include <bcm/vlan.h> 41 #include <bcm/l2.h> 42 #include <bcm/mcast.h> 43 #include <bcm/pkt.h> 44 #include <bcm/stack.h> 45 46 #include "socend.h" 47 48 /* 49 * TX and RX packet snooping/filter functions. 50 * 51 * For RX snooping, the function may return "handled" or "owned" 52 * in which case no further processing is done. If RX snoop returns 53 * "not handled", then "enqueue" must be set to TRUE or FALSE to 54 * indicate if packet should be enqueued via netJobAdd. 55 */ 56 57 static socend_snoop_ip_tx_t snoop_ip_tx = NULL; 58 static socend_snoop_ip_rx_t snoop_ip_rx = NULL; 59 60 int socend_cos_default = SOCEND_COS_DEFAULT; 61 int socend_cos_map[BCM_COS_COUNT] = SOCEND_COS_MAP_DEFAULT; 62 63 /* 64 * Define END_OBJ parameter type for each of the VxWorks platform. This method 65 * provides the best type checking for Tornado II. 66 */ 67 #if VX_VERSION == 531 68 # define _END_OBJ_PAR void 69 #else 70 # define _END_OBJ_PAR END_OBJ 71 #endif 72 73 #define SOC_END_HANDLER_PRIO_BASE 100 74 #define SOC_END_HANDLER_PRIO_COUNT 100 75 76 /* 77 * Define: dv_end_mblk/dv_end_se 78 * Purpose: Defines the dv_t usable entires for a pointer 79 * to the mblk structure if one is associated with 80 * the DMA, and the "se" pointer. 81 */ 82 #define dv_end_mblk dv_public1.ptr 83 #define dv_end_se dv_public2.ptr 84 85 END_OBJ *socend_load(char *is, void* ap); 86 87 STATUS socend_unload(_END_OBJ_PAR *); 88 STATUS socend_ioctl(_END_OBJ_PAR *, int cmd, caddr_t data); 89 STATUS socend_send(_END_OBJ_PAR *, M_BLK_ID mb); 90 STATUS socend_start(_END_OBJ_PAR *p); 91 STATUS socend_stop(_END_OBJ_PAR *p); 92 STATUS socend_poll_send(_END_OBJ_PAR *p, M_BLK_ID mb); 93 STATUS socend_poll_receive(_END_OBJ_PAR *p, M_BLK_ID mb); 94 STATUS socend_mcast_add(_END_OBJ_PAR *p, char *a); 95 STATUS socend_mcast_del(_END_OBJ_PAR *p, char *a); 96 STATUS socend_mcast_get(_END_OBJ_PAR *p, MULTI_TABLE *mt); 97 M_BLK_ID socend_address_form(M_BLK_ID mb, M_BLK_ID sa, M_BLK_ID da); 98 STATUS socend_data_get(M_BLK_ID mb, LL_HDR_INFO *h); 99 STATUS socend_addr_get(M_BLK_ID mb, M_BLK_ID sa, M_BLK_ID da, 100 M_BLK_ID esa, M_BLK_ID eda); 101 bcm_rx_t socend_receive(int unit, bcm_pkt_t *pkt, void *cookie); 102 int _socend_l2_lookup(int unit, bcm_mac_t mac, vlan_id_t vid, 103 bcm_pkt_t *pkt); 104 105 typedef STATUS (*_socend_fun_t) (void *p); 106 /* 107 * Variable: socend_netfuncs 108 * Purpose: Provides function switch entires for SOC devices. 109 */ 110 static NET_FUNCS socend_netfuncs = { 111 socend_start, /* Start Function */ 112 socend_stop, /* Stop Function */ 113 socend_unload, /* Unload function */ 114 socend_ioctl, /* IOCTL function */ 115 socend_send, /* Send Function */ 116 socend_mcast_add, /* Add mcast address function */ 117 socend_mcast_del, /* Delete mcast address function */ 118 socend_mcast_get, /* Get mcast address function */ 119 socend_poll_send, /* Polling send function */ 120 socend_poll_receive, /* Poling receive function */ 121 endEtherAddressForm, /* Address formation function */ 122 endEtherPacketDataGet, /* Packet data get function */ 123 endEtherPacketAddrGet /* Packet address get function */ 124 }; 125 126 /* 127 * Typedef: seu_t (SOC End Unit) 128 * Purpose: Group together items specific to a device, not an interface 129 */ 130 typedef struct seu_s { 131 uint32 seu_init; /* Initialized */ 132 socend_t *seu_devices; /* Linked list of devices */ 133 M_CL_CONFIG seu_blks; /* mBlks/clBlks */ 134 CL_DESC seu_cluster; /* cluster memory */ 135 CL_POOL_ID seu_clpool_id; /* Cluster Pool ID */ 136 NET_POOL_ID seu_netpool_id; /* Net Pool ID */ 137 #if defined(__mips__) 138 void *pkt_align_buf; /* Tmp buffer to word align IP pkt */ 139 #endif /* __mips__ */ 140 } seu_t; 141 142 typedef struct socend_prio_map_s { 143 int valid; 144 socend_t *socend; 145 } socend_prio_map_t; 146 147 /* 148 * Variable: socend_seu 149 * Purpose: One entry for each soc unit to not allow ont unit to 150 * use up all memory, and keep reference counts. 151 * Notes: Since the driver only uses one size of cluster, each 152 * element in the array for for a different SOC unit. 153 */ 154 static seu_t socend_seu[BCM_MAX_NUM_UNITS]; 155 156 static sal_mac_addr_t mac_zero = {0, 0, 0, 0, 0, 0}; 157 static sal_mac_addr_t mac_ones = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 158 static int set_target_broadcast = 0; 159 160 static socend_prio_map_t socend_prio_map[SOC_END_HANDLER_PRIO_COUNT]; 161 162 #if defined(BROADCOM_DEBUG) 163 164 void 165 socend_snoop_ip_tx_register(socend_snoop_ip_tx_t snoop_func) 166 { 167 snoop_ip_tx = snoop_func; 168 } 169 170 void 171 socend_snoop_ip_tx_unregister(void) 172 { 173 snoop_ip_tx = NULL; 174 } 175 176 void 177 socend_snoop_ip_rx_register(socend_snoop_ip_rx_t snoop_func) 178 { 179 snoop_ip_rx = snoop_func; 180 } 181 182 void 183 socend_snoop_ip_rx_unregister(void) 184 { 185 snoop_ip_rx = NULL; 186 } 187 188 void 189 socend_set_dest_broadcast (int flag) 190 /* 191 * Function: socend_set_dest_broadcast 192 * Purpose: Dump memory pools. 193 * Parameters: flag 194 * Returns: Nothing 195 */ 196 { 197 if (flag) 198 set_target_broadcast = 1; 199 else 200 set_target_broadcast = 0; 201 } 202 203 void 204 socend_dump_pools(int u) 205 /* 206 * Function: socend_dump_pools 207 * Purpose: Dump memory pools. 208 * Parameters: u - unit # 209 * Returns: Nothing 210 */ 211 { 212 IMPORT void netPoolShow(NET_POOL_ID); 213 seu_t *seu = &socend_seu[u]; 214 215 if ((u < BCM_MAX_NUM_UNITS) && seu->seu_init) { 216 LOG_CLI((BSL_META_U(u, 217 "NET POOL: Unit %d\n"), u)); 218 netPoolShow(socend_seu[u].seu_netpool_id); 219 } else { 220 LOG_CLI((BSL_META_U(u, 221 "Invalid unit: %d\n"), u)); 222 } 223 } 224 225 #endif /* BROADCOM_DEBUG */ 226 227 static STATUS 228 socend_mempool_alloc(socend_t *se, int pksize, int clblks, int cl, int mblks) 229 /* 230 * Function: socend_mempool_alloc 231 * Purpose: Initialize END memory pools for the specified SOC. 232 * Parameters: u - unit number to initialize. 233 * pksize - Packet size to use, MUST BE MTU size or greater. 234 * clblks - number of cluster block headers this unit 235 * cl - number of actual cluster buffers this unit. 236 * mblks - number of mblks this unit. 237 * 238 * Returns: OK or error if failed. 239 * Notes: If already initialized, nothing is done. 240 */ 241 { 242 seu_t *seu = &socend_seu[se->se_unit]; 243 244 LOG_INFO(BSL_LS_SYS_END, 245 (BSL_META("socend_mempool_alloc: Unit %d %sinitialized\n"), 246 se->se_unit, seu->seu_init ? "" : "not ")); 247 /* 248 * If already done, skip the allocation and just assign the required 249 * values. 250 */ 251 if (!seu->seu_init) { 252 seu->seu_init = TRUE; 253 seu->seu_netpool_id = (NET_POOL_ID)sal_alloc(sizeof(NET_POOL), 254 "net_pool"); 255 256 /* First Initialize the CL configuration */ 257 258 seu->seu_blks.mBlkNum = mblks; 259 seu->seu_blks.clBlkNum= clblks; 260 seu->seu_blks.memSize = (mblks * (M_BLK_SZ + sizeof(long))) 261 + (clblks * (CL_BLK_SZ + sizeof(long))); 262 seu->seu_blks.memArea = sal_alloc(seu->seu_blks.memSize, "socend cl"); 263 264 /* Now initialize the actual cluster buffers that contain packets */ 265 266 seu->seu_cluster.clNum = cl; 267 seu->seu_cluster.clSize = pksize; 268 seu->seu_cluster.memSize = cl*(pksize + sizeof(long)) + sizeof(long); 269 270 if (SOC_IS_ESW(se->se_unit)) { 271 seu->seu_cluster.memArea = sal_dma_alloc(seu->seu_cluster.memSize, 272 "socend_mempool"); 273 } else { 274 seu->seu_cluster.memArea = memalign(4096, 275 seu->seu_cluster.memSize); 276 } 277 /* Now set up the pool and GO! */ 278 279 if (!seu->seu_blks.memArea || !seu->seu_cluster.memArea || 280 !seu->seu_netpool_id || 281 (OK != netPoolInit(seu->seu_netpool_id, &seu->seu_blks, 282 &seu->seu_cluster, 1, NULL))){ 283 LOG_CLI((BSL_META("socend_mempool_init: Failed for unit %d\n"), se->se_unit)); 284 if (seu->seu_blks.memArea) { 285 sal_free(seu->seu_blks.memArea); 286 } 287 if (seu->seu_cluster.memArea) { 288 sal_dma_free(seu->seu_cluster.memArea); 289 } 290 if (seu->seu_netpool_id) { 291 free(seu->seu_netpool_id); 292 } 293 bzero((void *)seu, sizeof(*seu)); 294 return(ERROR); 295 } 296 seu->seu_clpool_id = netClPoolIdGet(seu->seu_netpool_id, pksize, 297 FALSE); 298 } 299 300 se->se_eo.pNetPool = seu->seu_netpool_id; 301 302 return(OK); 303 } 304 305 static int 306 socend_packet_alloc(int u, int pksize, uint32 flags, void** buf) 307 /* 308 * Function: socend_packet_alloc 309 * Purpose: Allocate a packet buffer. 310 * Parameters: u - unit number to allocate packet for 311 * pksize - size of packet to allocate 312 * flags - Dont know yet .... 313 * Returns: pointer to packet or NULL. 314 */ 315 { 316 void *p; 317 seu_t *seu = &socend_seu[u]; 318 319 assert(pksize <= SOC_END_PK_SZ); 320 321 p = netClusterGet(seu->seu_netpool_id, seu->seu_clpool_id); 322 *buf = p; 323 return(0); 324 } 325 326 static int 327 socend_packet_free(int u, void *p) 328 /* 329 * Function: socend_packet_free 330 * Purpose: Free a packet buffer. 331 * Parameters: u - unit number to allocate packet for 332 * p - pointer to packet to free. 333 * cookie: If != NULL, this is a pointer to the mBlk. Free it. 334 * Else, it's a new buffer we allocated. netClFree it. 335 * Returns: Nothing 336 */ 337 { 338 seu_t *seu = &socend_seu[u]; 339 netClFree(seu->seu_netpool_id, p); 340 return 0; 341 } 342 343 struct end_object * 344 socend_load(char *is, void* ap) 345 /* 346 * Function: socend_load 347 * Purpose: Provides SENS load routine for SOC device. 348 * Parameters: is - initialization string. 349 * Returns: Pointer to VxWorks end_obj structure or NULL 350 */ 351 { 352 struct end_object *eo; 353 socend_t *se; /* Sock End Structure */ 354 seu_t *seu; 355 char dev_name[sizeof(eo->devObject.name)]; 356 char mac[6]; /* MAC address parsing */ 357 int net_unit; 358 char mac_str[MACADDR_STR_LEN]; 359 int i, column_count, rt; 360 361 if (NULL == is) { 362 LOG_CLI((BSL_META("socend_load: unexpected NULL pointer for device name\n"))); 363 return(NULL); 364 } else if ('\0' == *is) { /* Copy in our device name */ 365 strcpy(is, "sc"); 366 return(NULL); 367 } 368 LOG_INFO(BSL_LS_SYS_END, 369 (BSL_META("socend_load: %s\n"), is)); 370 371 /* 372 * Setup END structure 373 * 374 * NOTE NOTE NOTE: This call MUST use calloc or malloc, since the object 375 * is freed by VxWorks using free(); 376 */ 377 378 if (NULL == (se = malloc(sizeof(*se)))) { 379 LOG_CLI((BSL_META("socend_load: failed to allocate memory for %s\n"), is)); 380 return(NULL); 381 } 382 383 bzero((void *)se, sizeof(*se)); 384 eo = &se->se_eo; 385 386 net_unit = atoi(is); 387 is = index(is, ':') + 1; 388 389 /* Parse init string, format is "net_unit:bcm_unit:MAC_ADDR:vlan" */ 390 391 se->se_unit = atoi(is); 392 seu = &socend_seu[se->se_unit]; 393 is = index(is, ':') + 1; /* Onto net unit # */ 394 395 if ((se->se_unit >= BCM_MAX_NUM_UNITS) || !*is) { 396 LOG_CLI((BSL_META("socend_load: Invalid soc device: %d\n"), se->se_unit)); 397 free(se); 398 return(NULL); 399 } 400 401 /* Check if optional VLAN/MAC address */ 402 403 se->se_vlan = VLAN_ID_INVALID; 404 if (is) { 405 column_count = 0; 406 i = 0; 407 while (*is && i < MACADDR_STR_LEN - 1 && column_count <= 5) { 408 mac_str[i++] = *is; 409 if (*is++ == ':') { 410 column_count++; 411 } 412 } 413 mac_str[i] = '\0'; 414 if (column_count == 6) { 415 mac_str[i-1] = '\0'; 416 } 417 if (5 <= column_count) { 418 rt = parse_macaddr(mac_str, se->se_mac); 419 } else { 420 rt = -1; 421 } 422 if (rt) { 423 LOG_CLI((BSL_META("socend_load: Invalid MAC address specified: %s\n"), 424 mac_str)); 425 free(se); 426 return(NULL); 427 } 428 if (column_count == 6) { 429 se->se_vlan = atoi(is); 430 } 431 } else { 432 ENET_COPY_MACADDR(mac_zero, se->se_mac); 433 } 434 435 if (se->se_vlan == VLAN_ID_INVALID) { 436 bcm_vlan_t vid; 437 bcm_vlan_default_get(se->se_unit, &vid); 438 se->se_vlan = vid; 439 } 440 441 if (ERROR == END_OBJ_INIT(eo, (DEV_OBJ *)se, "sc", net_unit, 442 &socend_netfuncs, SOC_END_STRING)) { 443 LOG_CLI((BSL_META("socend_load: END_OBJ_INIT failed for %s\n"), dev_name)); 444 } 445 if (ERROR == END_MIB_INIT(eo, M2_ifType_ethernet_csmacd, (UCHAR *)mac, 446 sizeof(mac), ETHERMTU, SOC_END_SPEED)) { 447 LOG_CLI((BSL_META("socend_load: END_MIB_INIT failed for %s\n"), dev_name)); 448 } 449 450 socend_mempool_alloc(se, SOC_END_PK_SZ, SOC_END_CLBLKS, SOC_END_CLBUFS, 451 SOC_END_MBLKS); 452 453 /* Set Ready */ 454 455 END_OBJ_READY (eo, IFF_NOTRAILERS | IFF_MULTICAST | IFF_BROADCAST); 456 457 /* Queue off of seu structure */ 458 459 se->se_next = seu->seu_devices; 460 seu->seu_devices = se; 461 #if defined(__mips__) 462 if(SOC_IS_ESW(se->se_unit)) { 463 socend_packet_alloc(se->se_unit, SOC_END_PK_SZ, 0, 464 &seu->pkt_align_buf); 465 } 466 #endif /* __mips__ */ 467 return(eo); 468 } 469 470 STATUS 471 socend_unload(_END_OBJ_PAR *p) 472 /* 473 * Function: socend_unload 474 * Purpose: SENS Unload function for SOC devices. 475 * Parameters: p - pointer to VxWorks end_obj structure. 476 * Returns: Status 477 */ 478 { 479 struct end_object *eo = (struct end_object *)p; 480 socend_t *se = (socend_t *)eo->devObject.pDevice; 481 socend_t *se_cur, *se_prev; 482 seu_t *seu= &socend_seu[se->se_unit]; 483 484 LOG_INFO(BSL_LS_SYS_END, 485 (BSL_META("socend_unload: %s%d:\n"), eo->devObject.name, 486 eo->devObject.unit)); 487 488 END_OBJECT_UNLOAD(eo); 489 490 /* Remove from list of active devices */ 491 492 se_prev = NULL; 493 for (se_cur = seu->seu_devices; se_cur != se; se_cur = se_cur->se_next) { 494 if (se_cur == NULL) { 495 return(ERROR); 496 } 497 se_prev = se_cur; 498 } 499 500 if (se_prev) { /* Not head */ 501 se_prev->se_next = se->se_next; 502 } else { /* Head */ 503 seu->seu_devices = se->se_next; 504 } 505 506 return(OK); 507 } 508 509 STATUS 510 socend_ioctl(_END_OBJ_PAR *p, int cmd, caddr_t data) 511 /* 512 * Function: socend_ioctl 513 * Purpose: SENS IOCTL function for SOC devices. 514 * Parameters: p - pointer to VxWorks end_obj structure for device 515 * cmd - command to execute 516 * data - data or address of data for CMD. 517 * Returns: Status 518 */ 519 { 520 struct end_object *eo = (struct end_object *)p; 521 socend_t *se = (socend_t *)eo->devObject.pDevice; 522 STATUS error = OK; 523 int unit = se->se_unit; 524 525 LOG_INFO(BSL_LS_SYS_END, 526 (BSL_META_U(unit, 527 "socend_ioctl: unit %d\n"), se->se_unit)); 528 529 switch((unsigned int)cmd) { 530 case EIOCSFLAGS: 531 LOG_INFO(BSL_LS_SYS_END, 532 (BSL_META_U(unit, 533 "socend_ioctl: %s%d: EIOCSFLAGS(0x%x)\n"), 534 eo->devObject.name, eo->devObject.unit, (unsigned int)data)); 535 if ((long)data < 0) { /* Clearing flags? */ 536 END_FLAGS_CLR(eo, -(long)data); 537 } else { 538 END_FLAGS_SET(eo, (long)data); 539 } 540 break; 541 case EIOCGFLAGS: 542 LOG_INFO(BSL_LS_SYS_END, 543 (BSL_META_U(unit, 544 "socend_ioctl: %s%d: EIOCGFLAGS\n"), 545 eo->devObject.name, eo->devObject.unit)); 546 if (NULL == data) { 547 error = EINVAL; 548 } else { 549 *(int *)data = eo->flags; 550 } 551 break; 552 case EIOCSADDR: /* Set interface address */ 553 LOG_INFO(BSL_LS_SYS_END, 554 (BSL_META_U(unit, 555 "socend_ioctl: %s%d: EIOCSADDR\n"), 556 eo->devObject.name, eo->devObject.unit)); 557 if (NULL == data) { 558 error = EINVAL; 559 } else { 560 bcm_l2_addr_t l2addr; 561 int my_modid; 562 if (ENET_CMP_MACADDR(se->se_mac, mac_zero)) { 563 LOG_INFO(BSL_LS_SYS_END, 564 (BSL_META_U(unit, 565 "socend_ioctl: Deleting old mac address\n"))); 566 (void)bcm_l2_addr_delete(se->se_unit, se->se_mac, se->se_vlan); 567 } 568 ENET_COPY_MACADDR(data, se->se_mac); 569 LOG_INFO(BSL_LS_SYS_END, 570 (BSL_META_U(unit, 571 "socend_ioctl: Setting new mac address\n"))); 572 bcm_l2_addr_t_init(&l2addr, se->se_mac, se->se_vlan); 573 l2addr.port = CMIC_PORT(unit); 574 l2addr.flags = BCM_L2_STATIC; 575 bcm_stk_my_modid_get(se->se_unit, &my_modid); 576 l2addr.modid = my_modid; 577 if (0 > bcm_l2_addr_add(se->se_unit, &l2addr)) { 578 LOG_CLI((BSL_META_U(unit, 579 "socend_ioctl: mac_configure_address failed: " 580 "Network Device %s%d\n"), 581 eo->devObject.name, eo->devObject.unit)); 582 ENET_COPY_MACADDR(mac_zero, se->se_mac); 583 error = EIO; 584 break; 585 } 586 END_MIB_INIT(eo, M2_ifType_ethernet_csmacd, (uint8 *)data, 6, 587 ETHERMTU, SOC_END_SPEED); 588 } 589 break; 590 case EIOCGADDR: /* Get Interface address */ 591 LOG_INFO(BSL_LS_SYS_END, 592 (BSL_META_U(unit, 593 "socend_ioctl: %s%d: EIOCGADDR\n"), 594 eo->devObject.name, eo->devObject.unit)); 595 if (NULL == data) { 596 error = EINVAL; 597 } else { 598 bcopy((char *)eo->mib2Tbl.ifPhysAddress.phyAddress, 599 (char *)data, eo->mib2Tbl.ifPhysAddress.addrLength); 600 } 601 break; 602 case EIOCGFBUF: /* Get min 1st buf for chain */ 603 LOG_INFO(BSL_LS_SYS_END, 604 (BSL_META_U(unit, 605 "socend_ioctl: %s%d: EIOCGFBUF\n"), 606 eo->devObject.name, eo->devObject.unit)); 607 if (data == NULL) { 608 error = EINVAL; 609 } else { 610 *(int *)data = 32; 611 } 612 break; 613 case EIOCGMWIDTH: /* Get device memory witdh */ 614 LOG_INFO(BSL_LS_SYS_END, 615 (BSL_META_U(unit, 616 "socend_ioctl: %s%d: EIOCGMWIDTH\n"), 617 eo->devObject.name, eo->devObject.unit)); 618 if (NULL == data) { 619 error = EINVAL; 620 } else { 621 *(int *)data = 32; 622 } 623 break; 624 case EIOCMULTIADD: 625 case EIOCMULTIDEL: 626 case EIOCMULTIGET: 627 case EIOCPOLLSTART: 628 case EIOCPOLLSTOP: 629 LOG_INFO(BSL_LS_SYS_END, 630 (BSL_META_U(unit, 631 "socend_ioctl: %s%d: MULTI/POLL\n"), 632 eo->devObject.name, eo->devObject.unit)); 633 error = ENOSYS; 634 break; 635 case EIOCGMIB2: /* Get MIB2 Table */ 636 LOG_INFO(BSL_LS_SYS_END, 637 (BSL_META_U(unit, 638 "socend_ioctl: %s%d: EIOCGMIB2\n"), 639 eo->devObject.name, eo->devObject.unit)); 640 if (data == NULL) { 641 error = EINVAL; 642 } else { 643 bcopy ((char *)&eo->mib2Tbl, (char *)data, sizeof(eo->mib2Tbl)); 644 } 645 break; 646 case EIOCGNAME: /* Get device Name */ 647 LOG_INFO(BSL_LS_SYS_END, 648 (BSL_META_U(unit, 649 "socend_ioctl: %s%d: EIOCGNAME\n"), 650 eo->devObject.name, eo->devObject.unit)); 651 if (NULL == data) { 652 error = EINVAL; 653 } else { 654 bcopy(eo->devObject.name, (char *)data, 655 sizeof(eo->devObject.name)); 656 } 657 break; 658 case EIOCGHDRLEN: 659 if (NULL == data) { 660 error = EINVAL; 661 } else { 662 *(int *)data = ENET_TAGGED_HDR_LEN; 663 } 664 break; 665 #if VX_VERSION == 62 || VX_VERSION == 64 || VX_VERSION == 66 || VX_VERSION == 68 666 case EIOCGRCVJOBQ: 667 LOG_INFO(BSL_LS_SYS_END, 668 (BSL_META_U(unit, 669 "socend_ioctl: %s%d: EIOCGRCVJOBQ\n"), 670 eo->devObject.name, eo->devObject.unit)); 671 if (NULL == data) { 672 error = EINVAL; 673 } else { 674 END_RCVJOBQ_INFO *qinfo = (END_RCVJOBQ_INFO *)data; 675 LOG_INFO(BSL_LS_SYS_END, 676 (BSL_META_U(unit, 677 "socend_ioctl: %s%d: numRcvJobQs input#: %d\n"), 678 eo->devObject.name, eo->devObject.unit, qinfo->numRcvJobQs)); 679 if (qinfo->numRcvJobQs < 1) { 680 error = ENOSPC; 681 } else { 682 qinfo->qIds[0] = netJobQueueId; 683 } 684 qinfo->numRcvJobQs = 1; 685 } 686 break; 687 #endif /* VX_VERSION */ 688 689 default: 690 LOG_INFO(BSL_LS_SYS_END, 691 (BSL_META_U(unit, 692 "socend_ioctl: %s%d: Unknown IOCTL\n"), 693 eo->devObject.name, eo->devObject.unit)); 694 error = EINVAL; 695 break; 696 } 697 LOG_INFO(BSL_LS_SYS_END, 698 (BSL_META_U(unit, 699 "socend_ioctl: %s%d: cmd=0x%x Return(%d)\n"), 700 eo->devObject.name, eo->devObject.unit, cmd, error)); 701 return(error); 702 } 703 704 void 705 socend_send_done(int unit, bcm_pkt_t *pkt, void *cookie) 706 /* 707 * Function: socend_send_done 708 * Purpose: Process a completion of a send request 709 * Parameters: unit - unit # 710 * pkt - The tx packet structure 711 * cookie - pointer to mBlk structure to free 712 * If null, assume we free the cluster directly. 713 * Returns: Nothing 714 * Notes: 715 * Assumption: This function is called from a non-interrupt context. 716 */ 717 { 718 LOG_INFO(BSL_LS_SYS_END, 719 (BSL_META_U(unit, 720 "Socend send done, in. pkt %p. ck %p. "), 721 (void *)pkt->_pkt_data.data, (void *)cookie)); 722 if (NULL == cookie) { 723 if (SOC_IS_ESW(unit)) { 724 socend_packet_free(unit, pkt->_pkt_data.data); 725 } else { 726 soc_cm_sfree(unit, pkt->_pkt_data.data); 727 } 728 } else { 729 netMblkClChainFree(cookie); /* Free MBLK */ 730 } 731 sal_free(pkt); 732 LOG_INFO(BSL_LS_SYS_END, 733 (BSL_META_U(unit, 734 "out.\n"))); 735 } 736 737 STATUS 738 socend_send(_END_OBJ_PAR *p, M_BLK_ID mb) 739 /* 740 * Function: socend_send 741 * Purpose: SENS send packet interface to SOC device. 742 * Parameters: p - pointer to VxWorks end_obj structure for device 743 * mb - mBlk containing packet. 744 * Returns: OK/ERROR 745 * 746 * Notes: Since since we don't have scatter/gather capability right 747 * now, we must copy up the data into one clustered buffer. 748 * If Possible, we simply hand off the buffer. 749 */ 750 { 751 int rv; 752 struct end_object *eo = (struct end_object *)p; 753 socend_t *se = (socend_t *)eo->devObject.pDevice; 754 char *packet; 755 int l; 756 enet_hdr_t *eh; 757 void *cookie; 758 bcm_pkt_t *pkt; 759 760 if (NULL == (pkt = sal_alloc(sizeof(bcm_pkt_t), "bcm pkt"))) { 761 return(ENOMEM); 762 } 763 764 /* 765 * If there is more than one cluster, we must allocate another 766 * buffer and copy the data. 767 * 768 * Note: Requires entire ethernet header to be in first mblk. 769 */ 770 771 if (mb->mBlkHdr.mNext|| !ENET_TAGGED((enet_hdr_t *)mb->mBlkHdr.mData)) { 772 if (SOC_IS_ESW(se->se_unit)) { 773 socend_packet_alloc(se->se_unit,SOC_END_PK_SZ, 0, (void*)&packet); 774 } else { 775 packet = soc_cm_salloc(se->se_unit, SOC_END_PK_SZ, 776 "SOCEND_TX"); 777 } 778 if (NULL == (packet)) { 779 END_ERR_ADD(eo, MIB2_OUT_ERRS, +1); 780 netMblkClChainFree(mb); 781 return(ENOMEM); 782 } 783 784 cookie = NULL; 785 /* 786 * If packet is not tagged, build a tag now. 787 */ 788 eh = (enet_hdr_t *)packet; 789 if (!ENET_TAGGED((enet_hdr_t *)mb->mBlkHdr.mData)) { 790 791 792 /* Set COS to default here */ 793 l = ENET_TAG_SIZE + 794 netMblkToBufCopy(mb, packet + ENET_TAG_SIZE, NULL); 795 /* Copy MAC addresses */ 796 sal_memcpy(eh, mb->mBlkHdr.mData, sizeof(sal_mac_addr_t) * 2); 797 798 /* Set VLAN info */ 799 eh->en_tag_tpid = htons(ENET_DEFAULT_TPID); 800 eh->en_tag_ctrl = htons(VLAN_CTRL(0,0,se->se_vlan)); 801 eh->en_tag_len = 802 ((enet_hdr_t *)mb->mBlkHdr.mData)->en_untagged_len; 803 } else { 804 /* Just copy entire packet */ 805 806 /* Extract priority and map to COS here */ 807 l = netMblkToBufCopy(mb, packet, NULL); 808 } 809 810 if (set_target_broadcast && 811 sal_memcmp(eh->en_dhost, eh->en_shost, 6) == 0) { 812 sal_memcpy(eh->en_dhost, mac_ones, 6); 813 } 814 netMblkClChainFree(mb); /* Free MBLK */ 815 } else { 816 l = mb->mBlkHdr.mLen; 817 packet = mb->mBlkHdr.mData; 818 cookie = (void *)mb; 819 } 820 821 #if defined(BROADCOM_DEBUG) 822 if (LOG_CHECK(BSL_LS_SYS_END | BSL_INFO) && 823 LOG_CHECK(BSL_LS_SOC_PACKET | BSL_INFO)) { 824 d_packet_format("socend TX", DECODE_ETHER, packet, l, NULL); 825 } 826 #endif /* defined(BROADCOM_DEBUG) */ 827 828 if (snoop_ip_tx != NULL) { 829 snoop_ip_tx(se->se_unit, packet, l); 830 } 831 832 sal_memset(pkt, 0, sizeof(bcm_pkt_t)); 833 pkt->pkt_data = &(pkt->_pkt_data); 834 pkt->_pkt_data.len = l; 835 pkt->_pkt_data.data = (uint8 *)packet; 836 pkt->blk_count = 1; 837 pkt->unit = se->se_unit; 838 pkt->pkt_len = l; 839 SOC_PBMP_CLEAR(pkt->tx_pbmp); 840 SOC_PBMP_CLEAR(pkt->tx_upbmp); 841 SOC_PBMP_CLEAR(pkt->tx_l3pbmp); 842 843 /* get tx_pbmp, tx_upbmp */ 844 eh = (enet_hdr_t *)packet; 845 rv = _socend_l2_lookup(se->se_unit, 846 eh->en_dhost, 847 VLAN_CTRL_ID(se->se_vlan), 848 pkt); 849 if(rv == ERROR){ 850 LOG_CLI((BSL_META("socend_send : can't get egress port(s) by _socend_l2_lookup.\n"))); 851 return(ERROR); 852 } 853 854 pkt->cookie = cookie; 855 pkt->call_back = socend_send_done; 856 pkt->flags &= ~BCM_TX_CRC_FLD; 857 pkt->flags |= BCM_TX_CRC_APPEND; 858 859 if ((rv = bcm_tx(se->se_unit, pkt, cookie)) != BCM_E_NONE) { 860 LOG_ERROR(BSL_LS_SOC_COMMON, 861 (BSL_META("bcm_tx failed: Unit %d: %s\n"), 862 se->se_unit, bcm_errmsg(rv))); 863 return(ERROR); 864 } 865 866 return(OK); 867 } 868 869 STATUS 870 socend_start(_END_OBJ_PAR *p) 871 /* 872 * Function: socend_start 873 * Purpose: SENS interface to activate a SOC interface. 874 * Parameters: p - pointer to VxWorks end_obj structure for device 875 * Returns: OK/ERROR 876 * 877 * Notes: 878 */ 879 { 880 int rv; 881 struct end_object *eo = (struct end_object *)p; 882 socend_t *se = (socend_t *)eo->devObject.pDevice; 883 bcm_l2_addr_t l2addr; 884 int i; 885 int my_modid; 886 887 LOG_INFO(BSL_LS_SYS_END, 888 (BSL_META("socend_start: Device(%s), unit %d\n"), 889 eo->devObject.name, se->se_unit)); 890 if (!ENET_CMP_MACADDR(se->se_mac, mac_zero)) { 891 LOG_CLI((BSL_META("socend_start: No valid mac address assigned: " 892 "Network Device %s%d\n"), 893 eo->devObject.name, eo->devObject.unit)); 894 } 895 896 bcopy((char *)se->se_mac, (char *)eo->mib2Tbl.ifPhysAddress.phyAddress, 897 eo->mib2Tbl.ifPhysAddress.addrLength); 898 899 LOG_INFO(BSL_LS_SYS_END, 900 (BSL_META("socend_start: Starting bcm_rx\n"))); 901 if (!bcm_rx_active(se->se_unit)) { 902 903 bcm_rx_cfg_t rx_cfg; 904 905 bcm_rx_cfg_get(se->se_unit, &rx_cfg); 906 rx_cfg.pkt_size = SOC_END_PK_SZ; 907 rx_cfg.rx_alloc = socend_packet_alloc; 908 rx_cfg.rx_free = socend_packet_free; 909 910 if ((rv= bcm_rx_start(se->se_unit, &rx_cfg)) < 0) { 911 LOG_CLI((BSL_META("rxmon: Error: Cannot start RX: %s.\n"), bcm_errmsg(rv))); 912 return(ERROR); 913 } 914 }else { 915 LOG_CLI((BSL_META("RX Thread is already running\n"))); 916 } 917 918 LOG_INFO(BSL_LS_SYS_END, 919 (BSL_META("socend_start: adding l2 addr\n"))); 920 bcm_l2_addr_t_init(&l2addr, se->se_mac, se->se_vlan); 921 l2addr.port = CMIC_PORT(se->se_unit); 922 l2addr.flags = BCM_L2_STATIC; 923 bcm_stk_my_modid_get(se->se_unit, &my_modid); 924 l2addr.modid = my_modid; 925 rv = bcm_l2_addr_add(se->se_unit, &l2addr); 926 if (rv < 0) { 927 LOG_CLI((BSL_META("socend_start: %s%d bcm_l2_addr_add failed: %s\n"), 928 eo->devObject.name, eo->devObject.unit, bcm_errmsg(rv))); 929 return(ERROR); 930 } 931 932 LOG_INFO(BSL_LS_SYS_END, 933 (BSL_META("socend_start: registering with bcm_rx\n"))); 934 for (i = 0; i < SOC_END_HANDLER_PRIO_COUNT; i++) { 935 if (socend_prio_map[i].valid != TRUE){ 936 socend_prio_map[i].valid = TRUE; 937 socend_prio_map[i].socend = se; 938 break; 939 } 940 } 941 942 if(i == SOC_END_HANDLER_PRIO_COUNT){ 943 LOG_CLI((BSL_META("socend_start: socend count is larger %d\n"), SOC_END_HANDLER_PRIO_COUNT)); 944 return(ERROR); 945 } 946 947 /* Register call back */ 948 if (SOC_IS_ESW(se->se_unit)) { 949 rv = bcm_rx_register(se->se_unit, "SOCEND", socend_receive, 950 (i + SOC_END_HANDLER_PRIO_BASE), 951 (void *)se, BCM_RCO_F_ALL_COS); 952 } else { 953 rv = bcm_rx_register(se->se_unit, "SOCEND", socend_receive, 954 (i + SOC_END_HANDLER_PRIO_BASE), 955 (void *)se, BCM_RCO_F_ALL_COS | BCM_RCO_F_INTR); 956 } 957 958 if (rv < 0) { 959 LOG_CLI((BSL_META("Warning: Could not register socend_receive from RX\n"))); 960 return(ERROR); 961 } 962 963 END_FLAGS_SET(eo, IFF_UP | IFF_RUNNING | IFF_BROADCAST); 964 LOG_INFO(BSL_LS_SYS_END, 965 (BSL_META("socend_start: Started Network Interface: %s%d\n"), 966 eo->devObject.name, eo->devObject.unit)); 967 return(OK); 968 } 969 970 STATUS 971 socend_stop(_END_OBJ_PAR *p) 972 /* 973 * Function: socend_stop 974 * Purpose: SENS interface to de-activate a SOC interface. 975 * Parameters: p - pointer to VxWorks end_obj structure for device 976 * Returns: OK/ERROR 977 */ 978 { 979 struct end_object *eo = (struct end_object *)p; 980 socend_t *se = (socend_t *)eo->devObject.pDevice; 981 ETHER_MULTI * pMCastNode; 982 983 int i, rv; 984 985 /* change to use bcm_rx */ 986 for (i = 0; i < SOC_END_HANDLER_PRIO_COUNT; i++) { 987 if ((uint32)socend_prio_map[i].socend == (uint32)se){ 988 socend_prio_map[i].valid = FALSE; 989 rv = bcm_rx_unregister(se->se_unit, socend_receive, i+SOC_END_HANDLER_PRIO_BASE); 990 if (rv < 0) { 991 LOG_CLI((BSL_META("Warning: Could not unregister socend_receive from RX\n"))); 992 return(ERROR); 993 } 994 break; 995 } 996 } 997 998 if(i == SOC_END_HANDLER_PRIO_COUNT){ 999 LOG_CLI((BSL_META("socend_stop: can't find the socend from socend_prio_map table\n"))); 1000 return(ERROR); 1001 } 1002 (void)bcm_l2_addr_delete(se->se_unit, se->se_mac, se->se_vlan); 1003 while ((pMCastNode = END_MULTI_LST_FIRST (eo)) != NULL) { 1004 socend_mcast_del(p, pMCastNode->addr); 1005 } 1006 END_FLAGS_CLR(eo, IFF_UP | IFF_RUNNING); 1007 LOG_INFO(BSL_LS_SYS_END, 1008 (BSL_META("socend_stop: Device(%s)\n"), eo->devObject.name)); 1009 return(OK); 1010 } 1011 1012 STATUS 1013 socend_poll_send(_END_OBJ_PAR *p, M_BLK_ID mb) 1014 /* 1015 * Function: socend_poll_send 1016 * Purpose: SENS interface to perform a polling send operation. 1017 * Parameters: p - pointer to VxWorks end_obj structure for device 1018 * mb - block data copied from. 1019 * Returns: OK/ERROR 1020 */ 1021 { 1022 struct end_object *eo = (struct end_object *)p; 1023 socend_t *se = (socend_t *)eo->devObject.pDevice; 1024 1025 LOG_CLI((BSL_META("socend_poll_send 0x%x 0x%x\n"), (int)se, (int)eo)); 1026 return(ENOSYS); 1027 } 1028 1029 STATUS 1030 socend_poll_receive(_END_OBJ_PAR *p, M_BLK_ID mb) 1031 /* 1032 * Function: socend_poll_receive 1033 * Purpose: SENS interface to perform a polling receive operation. 1034 * Parameters: p - pointer to VxWorks end_obj structure for device 1035 * mb - block data copied into. 1036 * Returns: OK/ERROR 1037 */ 1038 { 1039 struct end_object *eo = (struct end_object *)p; 1040 socend_t *se = (socend_t *)eo->devObject.pDevice; 1041 1042 LOG_CLI((BSL_META("socend_poll_receive 0x%x 0x%x\n"), (int)se, (int)eo)); 1043 return(ERROR); 1044 } 1045 1046 STATUS 1047 socend_mcast_add(_END_OBJ_PAR *p, char *a) 1048 /* 1049 * Function: socend_mcast_add 1050 * Purpose: SENS interface to add a multicast address for the interface. 1051 * Parameters: p - pointer to VxWorks end_obj structure for device 1052 * a - pointer to address to add 1053 * Returns: OK/ERROR 1054 */ 1055 { 1056 struct end_object *eo = (struct end_object *)p; 1057 socend_t *se = (socend_t *)eo->devObject.pDevice; 1058 int ret; 1059 pbmp_t pbmp, ubmp; 1060 bcm_mcast_addr_t mcaddr; 1061 char mac_str[MACADDR_STR_LEN]; 1062 int unit = se->se_unit; 1063 1064 if (LOG_CHECK(BSL_LS_SYS_END | BSL_INFO)) { 1065 format_macaddr(mac_str, (uint8 *)a); 1066 LOG_INFO(BSL_LS_SYS_END, 1067 (BSL_META_U(unit, 1068 "socend_mcast_add: %s%d %s\n"), 1069 eo->devObject.name, eo->devObject.unit, mac_str)); 1070 } 1071 /*soc_ioctl(ADD_MULTICAST)*/ 1072 if (ENETRESET == etherMultiAdd(&eo->multiList, a)) { 1073 BCM_PBMP_CLEAR(pbmp); 1074 BCM_PBMP_PORT_ADD(pbmp, CMIC_PORT(unit)); 1075 #if 0 1076 BCM_PBMP_PORT_ADD(pbmp, eo->devObject.unit); 1077 #endif 1078 BCM_PBMP_ASSIGN(ubmp, pbmp); 1079 bcm_mcast_addr_t_init(&mcaddr, (uint8 *)a, se->se_vlan); 1080 mcaddr.cos_dst = 0; 1081 BCM_PBMP_ASSIGN(mcaddr.pbmp, pbmp); 1082 BCM_PBMP_ASSIGN(mcaddr.ubmp, ubmp); 1083 ret = bcm_mcast_addr_add(se->se_unit, &mcaddr); 1084 if (ret >= BCM_E_NONE) { 1085 #if 0 1086 ret = bcm_amux_register(se->se_unit, a, se->se_vlan, 1087 socend_receive, (void *)se); 1088 #endif 1089 if (ret < 0) { 1090 LOG_CLI((BSL_META_U(unit, 1091 "socend_mcast_add: %s%d bcm_amux_register failed: %s\n"), 1092 eo->devObject.name, eo->devObject.unit, 1093 bcm_errmsg(ret))); 1094 bcm_mcast_addr_remove(se->se_unit, 1095 (uint8 *)a, se->se_vlan); 1096 } 1097 return (OK); 1098 } else { 1099 LOG_CLI((BSL_META_U(unit, 1100 "bcm_mcast_addr_add failed ERROR : %s\n"), 1101 bcm_errmsg(ret))); 1102 LOG_INFO(BSL_LS_SYS_END, 1103 (BSL_META_U(unit, 1104 "socend_mcast_add: Unit %d Device %s%d " 1105 "Software RESET\n"), 1106 se->se_unit, eo->devObject.name, eo->devObject.unit)); 1107 return (ERROR); 1108 } 1109 } 1110 return(ERROR); 1111 } 1112 1113 STATUS 1114 socend_mcast_del(_END_OBJ_PAR *p, char *a) 1115 /* 1116 * Function: socend_mcast_del 1117 * Purpose: SENS interface to add a multicast address for the interface. 1118 * Parameters: p - pointer to VxWorks end_obj structure for device 1119 * a - pointer to address to delete 1120 * Returns: OK/ERROR 1121 */ 1122 { 1123 struct end_object *eo = (struct end_object *)p; 1124 socend_t *se = (socend_t *)eo->devObject.pDevice; 1125 int ret; 1126 1127 if (ENETRESET == etherMultiDel(&eo->multiList, a)) { 1128 #if 0 1129 bcm_amux_unregister(se->se_unit, (uint8 *)a, se->se_vlan); 1130 #endif 1131 ret = bcm_mcast_addr_remove(se->se_unit, (uint8 *)a, se->se_vlan); 1132 if (ret == BCM_E_NONE) { 1133 return (OK); 1134 } else { 1135 LOG_CLI((BSL_META("bcm_mcast_addr_remove failed ERROR : %s\n"), 1136 bcm_errmsg(ret))); 1137 LOG_INFO(BSL_LS_SYS_END, 1138 (BSL_META("socend_mcast_del: Unit %d Device %s%d Software RESET\n"), 1139 se->se_unit, eo->devObject.name, eo->devObject.unit)); 1140 } 1141 } 1142 return(ENOSYS); 1143 } 1144 1145 STATUS 1146 socend_mcast_get(_END_OBJ_PAR *p, MULTI_TABLE *mt) 1147 /* 1148 * Function: socend_mcast_get 1149 * Purpose: SENS interface to get a multicast address for the interface. 1150 * Parameters: p - pointer to VxWorks end_obj structure for device 1151 * mt - pointer to multi table to fill in on return. 1152 * Returns: OK/ERROR 1153 */ 1154 { 1155 struct end_object *eo = (struct end_object *)p; 1156 1157 LOG_INFO(BSL_LS_SYS_END, 1158 (BSL_META("socend_mcast_get: %s%d\n"), eo->devObject.name, 1159 eo->devObject.unit)); 1160 1161 return(etherMultiGet(&eo->multiList, mt) == OK ? OK : ERROR); 1162 } 1163 1164 static void 1165 socend_untag(M_BLK_ID mb) 1166 /* 1167 * Function: socend_untag 1168 * Purpose: Untag an ethernet packet (if tagged) 1169 * Parameters: mb - MBLK containing packet. 1170 * Returns: Nothing 1171 * Notes: Assumes packet contiguous in one MBLK/CBLK. 1172 */ 1173 { 1174 enet_hdr_t *th, *uh; /* Tagged/Untagged header pointers */ 1175 const uint16 dec_length = sizeof(th->en_tag_ctrl)+sizeof(th->en_tag_len); 1176 1177 th = (enet_hdr_t *)mb->mBlkHdr.mData; 1178 if (ENET_TAGGED(th)) { /* If tagged - strip */ 1179 uh = (enet_hdr_t *)((char *)th + dec_length); 1180 sal_memcpy(uh->en_shost, th->en_shost, /* ORDER --- FIRST */ 1181 sizeof(th->en_shost)); 1182 sal_memcpy(uh->en_dhost, th->en_dhost, /* ORDER --- SECOND */ 1183 sizeof(th->en_dhost)); 1184 if (ENET_LEN(uh)) { 1185 uh->en_untagged_len = th->en_tag_len; 1186 } 1187 mb->mBlkHdr.mData += dec_length; /* Update SENS pointer */ 1188 mb->mBlkPktHdr.len = 1189 mb->mBlkHdr.mLen -= dec_length; /* Update SENS length */ 1190 } 1191 } 1192 1193 void 1194 socend_receive_netjob(int pi, int pckti, int pckt_size) 1195 /* 1196 * Function: socend_receive_netjob 1197 * Purpose: Called from netjob after packet arrives. 1198 * Parameters: p - pointer to (se), cookied passed on registration 1199 * pckpi - pointer to packet data (int form). 1200 * pckt_size - received length of packet. 1201 * Returns: Nothing 1202 */ 1203 { 1204 socend_t *se = (socend_t *)pi; 1205 struct end_object *eo = &se->se_eo; 1206 void *pckt = (void *)pckti; 1207 bcm_vlan_t vid; 1208 CL_BLK_ID cb = NULL; 1209 M_BLK_ID mb = NULL; 1210 1211 /* Check the DCB for errors */ 1212 #if defined(BROADCOM_DEBUG) /* Only compile in for debug */ 1213 if (LOG_CHECK(BSL_LS_SYS_END | BSL_INFO) && 1214 LOG_CHECK(BSL_LS_SOC_PACKET | BSL_INFO)) { 1215 d_packet_format("socend RX", DECODE_ETHER, pckt, pckt_size, NULL); 1216 } 1217 #endif /* BROADCOM_DEBUG */ 1218 /* 1219 * Build Cluster - then attach to mblks, 1 for each interface that 1220 * should get the packet. Broadcast/Multicast packets go up all the stacks. 1221 * 1222 * For multicast, it should only go up stacks that have registered for that 1223 * address, but for now, this will allow multiple interfaces to work. 1224 */ 1225 1226 if ((NULL == (cb = netClBlkGet(eo->pNetPool, M_DONTWAIT)))) { 1227 if (mb) netMblkFree(eo->pNetPool, mb); 1228 netClFree(eo->pNetPool, pckt); /* Free packet */ 1229 END_ERR_ADD(eo, MIB2_IN_ERRS, +1); 1230 return; 1231 } 1232 1233 #if defined(__mips__) 1234 if (SOC_IS_ESW(se->se_unit)) 1235 { 1236 seu_t *seu = &socend_seu[se->se_unit]; 1237 void *tmp; 1238 1239 sal_memcpy((UINT8 *)seu->pkt_align_buf + 2, (UINT8 *)pckt, pckt_size); 1240 1241 tmp = seu->pkt_align_buf; 1242 seu->pkt_align_buf = pckt; 1243 pckt = tmp; 1244 } 1245 #endif /* __mips__ */ 1246 1247 /* 1 MBLK for each interface */ 1248 1249 if ((mb = mBlkGet(eo->pNetPool, M_DONTWAIT, MT_DATA))) { 1250 netClBlkJoin(cb, pckt, SOC_END_PK_SZ, NULL, 0, 0, 0); 1251 netMblkClJoin(mb, cb); 1252 mb->mBlkPktHdr.len = mb->mBlkHdr.mLen = pckt_size; 1253 mb->mBlkHdr.mFlags |= M_PKTHDR; 1254 #if defined(__mips__) 1255 if (SOC_IS_ESW(se->se_unit)) { 1256 mb->mBlkHdr.mData +=2; 1257 } 1258 #endif /* __mips__ */ 1259 vid = VLAN_CTRL_ID(soc_ntohs(((enet_hdr_t *)mb->mBlkHdr.mData)->en_tag_ctrl)); 1260 if (SOC_IS_ESW(se->se_unit)) { 1261 socend_untag(mb); /* Untag packet for now */ 1262 } 1263 } else { 1264 netClBlkFree(eo->pNetPool, cb); 1265 netClFree(eo->pNetPool, pckt); /* Free packet */ 1266 return; 1267 } 1268 1269 { 1270 M_BLK_ID tmb, fmb = mb; 1271 seu_t *seu = &socend_seu[se->se_unit]; 1272 /* 1273 * Duplicate MBLK, and point to same cluster. 1274 */ 1275 for (se = seu->seu_devices; se != NULL; se = se->se_next) { 1276 1277 if (vid != se->se_vlan) { 1278 continue; 1279 } 1280 1281 eo = &se->se_eo; 1282 1283 if (se->se_next != NULL) { 1284 tmb = mBlkGet(eo->pNetPool, M_DONTWAIT, MT_DATA); 1285 netMblkDup(mb, tmb); 1286 } else { 1287 fmb = NULL; 1288 tmb = mb; 1289 } 1290 1291 END_RCV_RTN_CALL(eo, tmb); 1292 } 1293 1294 if (fmb) { 1295 netMblkClFree(fmb); 1296 } 1297 } 1298 } 1299 1300 /* 1301 * Function: socend_receive 1302 * Purpose: Called Address mux when packet matches MAC address. 1303 * Parameters: unit - StrataSwitch unit # 1304 * port - StrataSwitch port # 1305 * cookie 1306 * reason - 1307 * packet - 1308 * length 1309 * Returns: 1310 * BCM_RX_HANDLED - packet received for unknown reason 1311 * BCM_RX_HANDLED_OWNED - packet owned. 1312 */ 1313 1314 bcm_rx_t 1315 socend_receive(int unit, bcm_pkt_t *pkt, void *cookie) 1316 { 1317 #define OK_REASON ((uint32)(-1)) 1318 1319 /* 1320 * Was: 1321 * (DMAS1_OP_IPSW | DMAS1_OP_IPINF | DMAS1_OP_IPMC | \ 1322 * DMAS1_OP_TTL | BCM_PMUX_PR_DEFIP | BCM_PMUX_PR_COSMK | \ 1323 * DMAS1_OP_BCA) 1324 */ 1325 1326 int pkt_rv = BCM_RX_NOT_HANDLED; 1327 int rv; 1328 int enqueue = TRUE; 1329 1330 if (pkt->rx_reason & ~OK_REASON) { 1331 return BCM_RX_NOT_HANDLED; 1332 } 1333 1334 /* Check VLAN for match; Check dest MAC for match; check for bcast */ 1335 1336 if (snoop_ip_rx != NULL) { 1337 pkt_rv = snoop_ip_rx(unit, pkt, &enqueue); 1338 } 1339 1340 if (pkt_rv == BCM_RX_NOT_HANDLED && enqueue) { 1341 if (SOC_IS_ESW(unit)) { 1342 rv = netJobAdd((FUNCPTR)socend_receive_netjob, 1343 (int)cookie, 1344 (int)pkt->pkt_data[0].data, 1345 (int)pkt->pkt_len, 1346 4, 1347 5); 1348 pkt_rv = ((rv == OK) ? BCM_RX_HANDLED_OWNED : BCM_RX_NOT_HANDLED); 1349 } else { 1350 char *packet; 1351 1352 socend_packet_alloc(unit, SOC_END_PK_SZ, 0, (void *)&packet); 1353 if (NULL == packet){ 1354 LOG_INFO(BSL_LS_SYS_END, 1355 (BSL_META_U(unit, 1356 "failed to allocate buffer with socend_packet_alloc\n"))); 1357 return BCM_RX_NOT_HANDLED; 1358 } 1359 sal_memset(packet, 0x0, SOC_END_PK_SZ); 1360 sal_memcpy(packet, (unsigned char *)pkt->pkt_data[0].data, 1361 pkt->pkt_len); 1362 rv = netJobAdd((FUNCPTR)socend_receive_netjob, 1363 (int)cookie, 1364 (int)packet, 1365 (int)pkt->pkt_len, 1366 4, 1367 5); 1368 LOG_INFO(BSL_LS_SYS_END, 1369 (BSL_META_U(unit, 1370 "netJobAdd rv=0x%x OK=%x\n"), rv, OK)); 1371 pkt_rv = BCM_RX_HANDLED; 1372 } 1373 } 1374 1375 return pkt_rv; 1376 } 1377 1378 /* 1379 * Function: 1380 * _socend_l2_lookup 1381 * Purpose: 1382 * Determine packets egress port(s) based on MAC and VLAN ID 1383 * Parameters: 1384 * unit - StrataSwitch Unit #. 1385 * mac - mac address of destination. 1386 * vid - VLAN ID of destination. 1387 * pkt - Where the port bitmaps are stored 1388 * Returns: 1389 * OK/ERROR 1390 * Notes: 1391 */ 1392 1393 int 1394 _socend_l2_lookup(int unit, bcm_mac_t mac, vlan_id_t vid, 1395 bcm_pkt_t *pkt) 1396 { 1397 int rv = OK; 1398 bcm_port_t port = 0; 1399 pbmp_t raw_pbm; 1400 pbmp_t l_pbm; 1401 pbmp_t l_upbm; 1402 pbmp_t l_l3pbm; /* To be implemented */ 1403 bcm_mcast_addr_t mcaddr; 1404 bcm_module_t modid = 0; 1405 int my_modid; 1406 1407 BCM_PBMP_CLEAR(raw_pbm); 1408 BCM_PBMP_CLEAR(l_pbm); 1409 BCM_PBMP_CLEAR(l_upbm); 1410 BCM_PBMP_CLEAR(l_l3pbm); 1411 1412 bcm_stk_my_modid_get(unit, &my_modid); 1413 if (ENET_MACADDR_UNICAST(mac)) { 1414 bcm_l2_addr_t l2addr; 1415 1416 pkt->opcode = BCM_HG_OPCODE_UC; 1417 bcm_l2_addr_t_init(&l2addr, mac, vid); 1418 rv = bcm_l2_addr_get(unit, mac, vid, &l2addr); 1419 modid = l2addr.modid; 1420 port = (modid == my_modid) ? l2addr.port : IPIC_PORT(unit); 1421 1422 BCM_PBMP_ASSIGN(pkt->dest_mod, modid); 1423 BCM_PBMP_ASSIGN(pkt->dest_port, l2addr.port); 1424 1425 if (rv >= 0) { /* Determine if it's going out untagged */ 1426 rv = bcm_vlan_port_get(unit, vid, &l_pbm, &l_upbm); 1427 BCM_PBMP_CLEAR(l_pbm); 1428 BCM_PBMP_PORT_ADD(l_pbm, port); 1429 } else { /* combine all error return values */ 1430 rv = ERROR; 1431 } 1432 } else if (ENET_MACADDR_MULTICAST(mac)) { 1433 pkt->opcode = BCM_HG_OPCODE_MC; 1434 rv = bcm_mcast_port_get(unit, mac, vid, &mcaddr); 1435 if (rv >= 0) { 1436 } else { /* combine all error return values */ 1437 rv = ERROR; 1438 } 1439 BCM_PBMP_ASSIGN(raw_pbm, mcaddr.pbmp); 1440 BCM_PBMP_ASSIGN(l_pbm, mcaddr.pbmp); 1441 BCM_PBMP_ASSIGN(l_upbm, mcaddr.ubmp); 1442 } else if (ENET_MACADDR_BROADCAST(mac)) { 1443 pkt->opcode = BCM_HG_OPCODE_BC; 1444 rv = ERROR; 1445 } else { 1446 rv = ERROR; 1447 } 1448 1449 switch(rv) { 1450 case ERROR: 1451 /* 1452 * If no match was found, then spray out all ports in vlan. 1453 */ 1454 rv = bcm_vlan_port_get(unit, vid, &l_pbm, &l_upbm); 1455 if (rv >= 0) { 1456 rv = OK; 1457 } else { /* combine all error return values */ 1458 rv = ERROR; 1459 } 1460 break; 1461 default: 1462 break; 1463 } 1464 1465 BCM_PBMP_PORT_REMOVE(l_pbm, CMIC_PORT(unit)); /* Never back to us */ 1466 1467 pkt->flags |= BCM_TX_SRC_MOD; 1468 BCM_PBMP_ASSIGN(pkt->src_mod, my_modid); 1469 pkt->flags |= BCM_TX_SRC_PORT; 1470 BCM_PBMP_ASSIGN(pkt->src_port, CMIC_PORT(unit)); 1471 BCM_PBMP_ASSIGN(pkt->tx_pbmp, l_pbm); 1472 BCM_PBMP_ASSIGN(pkt->tx_upbmp, l_upbm); 1473 BCM_PBMP_ASSIGN(pkt->tx_l3pbmp, l_l3pbm); /* Always 0 for now */ 1474 1475 return(rv); 1476 } 1477