openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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