LOCAL STATUS NetdrvPollRcv(END_DEVICE * pDrvCtrl, /* device to be polled */ M_BLK_ID pMblk) /* ptr to buffer */ { u_short stat; char* pPacket; int len; DRV_LOG (DRV_DEBUG_POLL_RX, "NetdrvPollRcv ....... Not Implemented\n", 1, 2, 3, 4, 5, 6); stat = NetdrvStatusRead(pDrvCtrl); if (!(stat & NETDRV_RINT)) { printf("\r\nNetdrvPollRcv no data"); return (EAGAIN); } /* Get packet and length from device buffer/descriptor */ pPacket = NULL; /* DUMMY CODE */ len = 64; /* DUMMY CODE */ /* Upper layer must provide a valid buffer. */ if ((pMblk->mBlkHdr.mLen < len) || (!(pMblk->mBlkHdr.mFlags & M_EXT))) { #ifdef BOOTROM_DEBUG printf("\r\nPRX bad mblk"); #endif return (EAGAIN); } END_ERR_ADD(&pDrvCtrl->end, MIB2_IN_UCAST, +1); bcopy (pPacket, pMblk->m_data, len); pMblk->mBlkHdr.mFlags |= M_PKTHDR; /* set the packet header */ pMblk->mBlkHdr.mLen = len; /* set the data len */ pMblk->mBlkPktHdr.len = len; /* set the total len */ #ifdef BOOTROM_DEBUG printf("\r\nNetdrvPollRcv OK"); #endif return (OK); }
LOCAL STATUS mirrorEndPollSend ( END_CTRL* pDrvCtrl, M_BLK* pMblk ) { STATUS status; /* mirror 1 should not call this function */ if (pDrvCtrl->unit != 0) return ERROR; /* call the poll routine in the real device */ status = pDrvCtrl->pPhyEnd->pFuncTable->pollSend(pDrvCtrl->pPhyEnd, pMblk); /* Bump the statistic counter. */ END_ERR_ADD(&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1); return OK; }
LOCAL STATUS NetdrvPollSend(END_DEVICE* pDrvCtrl, /* device to be polled */ M_BLK_ID pMblk /* packet to send */) { int len; u_short stat; #ifdef BOOTROM_DEBUG printf("\r\nNetdrvPollSend"); #endif stat = NetdrvStatusRead(pDrvCtrl); /* dummy code */ if((stat & NETDRV_TINT) == 0) { return ((STATUS) EAGAIN); } len = max(ETHERSMALL, pMblk->m_len); /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); /* Free the data if it was accepted by device */ netMblkClFree (pMblk); #ifdef BOOTROM_DEBUG printf("\r\nleaving NetdrvPollSend"); #endif return (OK); }
LOCAL STATUS NetdrvSend(END_DEVICE * pDrvCtrl, M_BLK_ID pMblk) { unsigned char *pucPktData=NULL; uint32 len = 0; uint32 ulPort = -1; ULONG ulRet=OK; unsigned int unit = 0; int i; /* taskDelay(0); */ #ifdef BOOTROM_DEBUG PRINTF_DEBUG2("NetdrvSend\n"); /* DEL_ME */ #endif /* END_TX_SEM_TAKE(&pDrvCtrl->end, WAIT_FOREVER); */ if (pMblk->mBlkPktHdr.len > NETDRV_CL_LEN - 4) { ulRet = ERROR; goto sendErr; } pucPktData = sal_dma_alloc(NETDRV_CL_LEN, "pucPktData"); if (NULL==pucPktData) { ulRet = ERROR; goto sendErr; } /* memset(pucPktData, 0, NETDRV_CL_LEN); */ len = (ULONG)netMblkToBufCopy(pMblk, pucPktData, NULL); len = max(ETHERSMALL, len); for (unit = 0; unit < _n_devices; unit++) { if (pkt_bcm_tx(unit, pucPktData, len) != 0) { /* Synchronous TX */ printf("ERROR: fail to tx pkt unit %d\n", unit); ulRet = ERROR; goto sendErr; } } g_ulPktSend++; sendErr: netMblkClChainFree (pMblk); /* for the packet already sending, we don't want to free them */ if (NULL!=pucPktData) { cacheDmaFree(pucPktData); pucPktData = NULL; } /* END_TX_SEM_GIVE(&pDrvCtrl->end); */ /* Bump the statistic counter. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_OUT_UCAST, +1); return ulRet; }
/* * Send the received packet to END driver */ int NetdrvSendToEnd(bcm_pkt_t *pPkt) { int len; M_BLK_ID pMblk; char* pCluster = NULL; CL_BLK_ID pClBlk; END_DEVICE *pDrvCtrl = __netDriver; if (pDrvCtrl == NULL) { return ERROR; } /* Add one to our unicast data. */ END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_UCAST, +1); /* * We implicitly are loaning here, if copying is necessary this * step may be skipped, but the data must be copied before being * passed up to the protocols. */ pCluster = netClusterGet (pDrvCtrl->end.pNetPool, pDrvCtrl->pClPoolId); if (pCluster == NULL) { DRV_LOG (1, "Cannot loan!\n",1,2,3,4,5,6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* Grab a cluster block to marry to the cluster we received. */ if ((pClBlk = netClBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT)) == NULL) { netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pCluster); DRV_LOG (DRV_DEBUG_RX, "Out of Cluster Blocks!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* * OK we've got a spare, let's get an M_BLK_ID and marry it to the * one in the ring. */ if ((pMblk = mBlkGet (pDrvCtrl->end.pNetPool, M_DONTWAIT, MT_DATA)) == NULL) { netClBlkFree (pDrvCtrl->end.pNetPool, pClBlk); netClFree (pDrvCtrl->end.pNetPool, (UCHAR *)pCluster); DRV_LOG (DRV_DEBUG_RX, "Out of M Blocks!\n", 1, 2, 3, 4, 5, 6); END_ERR_ADD (&pDrvCtrl->end, MIB2_IN_ERRS, +1); goto cleanRXD; } /* remove tag */ len = pPkt->tot_len - 8; memcpy(pCluster + 2, (unsigned char *)(&(pPkt->_pkt_data.data[0])), 12); memcpy(pCluster + 14, (unsigned char *)(&(pPkt->_pkt_data.data[16])), len-12); /* Free buffer previously stolen */ bcm_rx_free(pPkt->unit, pPkt->_pkt_data.data); /* Join the cluster to the MBlock */ netClBlkJoin (pClBlk, pCluster, len, NULL, 0, 0, 0); netMblkClJoin (pMblk, pClBlk); pMblk->mBlkHdr.mLen = len; pMblk->mBlkHdr.mData += 2; pMblk->mBlkHdr.mFlags |= M_PKTHDR; pMblk->mBlkPktHdr.len = len; /* Send the packet to END driver */ END_RCV_RTN_CALL(&__netDriver->end, pMblk); g_ulPktUp++; return OK; cleanRXD: return (ERROR); }
LOCAL void mirrorEndReceive ( END_CTRL* pDrvCtrl, /* pointer to END_CTRL structure */ M_BLK* pMblk ) { UINT16 * pTmp; UINT16 enetAddr[3]; LOG_MSG("mirrorEndReceive: unit: %d, ", (int)pDrvCtrl->unit, 2, 3, 4, 5, 6); LOG_MSG("dst:%02X:%02X:%02X:%02X:%02X:%02X, ", *(UCHAR *)(pMblk->mBlkHdr.mData), *((UCHAR *)(pMblk->mBlkHdr.mData) + 1), *((UCHAR *)(pMblk->mBlkHdr.mData) + 2), *((UCHAR *)(pMblk->mBlkHdr.mData) + 3), *((UCHAR *)(pMblk->mBlkHdr.mData) + 4), *((UCHAR *)(pMblk->mBlkHdr.mData) + 5)); LOG_MSG("src:%02X:%02X:%02X:%02X:%02X:%02X\n", *((UCHAR *)(pMblk->mBlkHdr.mData) + 6), *((UCHAR *)(pMblk->mBlkHdr.mData) + 7), *((UCHAR *)(pMblk->mBlkHdr.mData) + 8), *((UCHAR *)(pMblk->mBlkHdr.mData) + 9), *((UCHAR *)(pMblk->mBlkHdr.mData) + 10), *((UCHAR *)(pMblk->mBlkHdr.mData) + 11)); /* don't allow the packet through if in polling mode */ if (pDrvCtrl->polling == TRUE) { netMblkClChainFree(pMblk); return; } /* if unit is not in promiscuous mode, filter packets to receive only * packets for our MAC address or broadcasts. */ if (pDrvCtrl->promiscuous == FALSE) { pTmp = (UINT16 *)(pMblk->mBlkHdr.mData); if (((UINT32)(pTmp) & 0x01) == 0) { /* address is aligned on a 2 or 4 byte boundary */ enetAddr[0] = pTmp[0]; enetAddr[1] = pTmp[1]; enetAddr[2] = pTmp[2]; } else { /* address is aligned on a byte-boundary */ bcopy((char *)pTmp, (char *)enetAddr, 6); } if ((MAC_ADDR_EQ(enetAddr, pDrvCtrl->enetAddr) == 0) && (IS_BROADCAST(enetAddr) == 0) && (isInMulticastList(pDrvCtrl, enetAddr) == FALSE)) { LOG_MSG("Dest addr not my addr/broadcast/multicast - dropping!\n", 1, 2, 3, 4, 5, 6); netMblkClChainFree(pMblk); return; } } LOG_MSG("Sending up the packet to my network stack\n", 1, 2, 3, 4, 5, 6); /* send up to protocol */ END_RCV_RTN_CALL(&pDrvCtrl->endObject, pMblk); /* bump input packet counter */ END_ERR_ADD(&pDrvCtrl->endObject, MIB2_IN_UCAST, +1); }
LOCAL STATUS mirrorEndSend ( END_CTRL* pDrvCtrl, M_BLK* pMblk ) { int otherHalfOfMirror; int status = OK; LOG_MSG("mirrorEndSend: unit: %d, pollMode: %d, ", (int)pDrvCtrl->unit, (int)pDrvCtrl->polling, 4, 5, 6, 7); LOG_MSG("dst:%02X:%02X:%02X:%02X:%02X:%02X, ", *(UCHAR *)(pMblk->mBlkHdr.mData), *((UCHAR *)(pMblk->mBlkHdr.mData) + 1), *((UCHAR *)(pMblk->mBlkHdr.mData) + 2), *((UCHAR *)(pMblk->mBlkHdr.mData) + 3), *((UCHAR *)(pMblk->mBlkHdr.mData) + 4), *((UCHAR *)(pMblk->mBlkHdr.mData) + 5)); LOG_MSG("src:%02X:%02X:%02X:%02X:%02X:%02X\n", *((UCHAR *)(pMblk->mBlkHdr.mData) + 6), *((UCHAR *)(pMblk->mBlkHdr.mData) + 7), *((UCHAR *)(pMblk->mBlkHdr.mData) + 8), *((UCHAR *)(pMblk->mBlkHdr.mData) + 9), *((UCHAR *)(pMblk->mBlkHdr.mData) + 10), *((UCHAR *)(pMblk->mBlkHdr.mData) + 11)); if (pDrvCtrl->polling == TRUE) { netMblkClChainFree (pMblk); /* free the given mBlk chain */ return ERROR; } otherHalfOfMirror = pDrvCtrl->unit ^ 1; /* 0->1, 1->0 */ if (channelState[otherHalfOfMirror] == CHANNEL_UP) { /* other half of mirror is up, send packet there */ if (pDrvCtrl->unit == MIRROR_STACK_UNIT_NUM) mirrorSendStatus = OK; /* * In the previous version of the Bridge, calling mirrorEndReceive * directly caused deadlock when bridge tries to flood multicasts * outgoing from local stack. One way to avoid the deadlock is to * call mirrorEndReceive from tNetTask by using netJobAdd. But this * causes performance hit, and also overloads the netJob ring buffer. * * The better solution is to call mirrorEndReceive directly, and * avoid deadlock by not taking the bridge port list semaphore when * flooding packets to all bridge ports. Taking this semaphore was * previously thought necessary to guard against removal of a bridge * port when the bridge is flooding packets to that port. The * possibility of this occurring is very small, and can be avoided * if the user makes sure the bridge port is free of incoming and * outgoing traffic before removing the bridge port. */ mirrorEndReceive(&drvCtrl[otherHalfOfMirror], pMblk); if (pDrvCtrl->unit == MIRROR_STACK_UNIT_NUM) status = mirrorSendStatus; } else { /* other half of mirror is not up, toss the packet */ netMblkClChainFree(pMblk); } /* Bump the statistic counter. */ END_ERR_ADD(&pDrvCtrl->endObject, MIB2_OUT_UCAST, +1); return status; }
STATUS socend_send(_END_OBJ_PAR *p, M_BLK_ID mb) /* * Function: socend_send * Purpose: SENS send packet interface to SOC device. * Parameters: p - pointer to VxWorks end_obj structure for device * mb - mBlk containing packet. * Returns: OK/ERROR * * Notes: Since since we don't have scatter/gather capability right * now, we must copy up the data into one clustered buffer. * If Possible, we simply hand off the buffer. */ { int rv; struct end_object *eo = (struct end_object *)p; socend_t *se = (socend_t *)eo->devObject.pDevice; char *packet; int l; enet_hdr_t *eh; void *cookie; bcm_pkt_t *pkt; if (NULL == (pkt = sal_alloc(sizeof(bcm_pkt_t), "bcm pkt"))) { return(ENOMEM); } /* * If there is more than one cluster, we must allocate another * buffer and copy the data. * * Note: Requires entire ethernet header to be in first mblk. */ if (mb->mBlkHdr.mNext|| !ENET_TAGGED((enet_hdr_t *)mb->mBlkHdr.mData)) { if (SOC_IS_ESW(se->se_unit)) { socend_packet_alloc(se->se_unit,SOC_END_PK_SZ, 0, (void*)&packet); } else { packet = soc_cm_salloc(se->se_unit, SOC_END_PK_SZ, "SOCEND_TX"); } if (NULL == (packet)) { END_ERR_ADD(eo, MIB2_OUT_ERRS, +1); netMblkClChainFree(mb); return(ENOMEM); } cookie = NULL; /* * If packet is not tagged, build a tag now. */ eh = (enet_hdr_t *)packet; if (!ENET_TAGGED((enet_hdr_t *)mb->mBlkHdr.mData)) { /* Set COS to default here */ l = ENET_TAG_SIZE + netMblkToBufCopy(mb, packet + ENET_TAG_SIZE, NULL); /* Copy MAC addresses */ sal_memcpy(eh, mb->mBlkHdr.mData, sizeof(sal_mac_addr_t) * 2); /* Set VLAN info */ eh->en_tag_tpid = htons(ENET_DEFAULT_TPID); eh->en_tag_ctrl = htons(VLAN_CTRL(0,0,se->se_vlan)); eh->en_tag_len = ((enet_hdr_t *)mb->mBlkHdr.mData)->en_untagged_len; } else { /* Just copy entire packet */ /* Extract priority and map to COS here */ l = netMblkToBufCopy(mb, packet, NULL); } if (set_target_broadcast && sal_memcmp(eh->en_dhost, eh->en_shost, 6) == 0) { sal_memcpy(eh->en_dhost, mac_ones, 6); } netMblkClChainFree(mb); /* Free MBLK */ } else { l = mb->mBlkHdr.mLen; packet = mb->mBlkHdr.mData; cookie = (void *)mb; } #if defined(BROADCOM_DEBUG) if (LOG_CHECK(BSL_LS_SYS_END | BSL_INFO) && LOG_CHECK(BSL_LS_SOC_PACKET | BSL_INFO)) { d_packet_format("socend TX", DECODE_ETHER, packet, l, NULL); } #endif /* defined(BROADCOM_DEBUG) */ if (snoop_ip_tx != NULL) { snoop_ip_tx(se->se_unit, packet, l); } sal_memset(pkt, 0, sizeof(bcm_pkt_t)); pkt->pkt_data = &(pkt->_pkt_data); pkt->_pkt_data.len = l; pkt->_pkt_data.data = (uint8 *)packet; pkt->blk_count = 1; pkt->unit = se->se_unit; pkt->pkt_len = l; SOC_PBMP_CLEAR(pkt->tx_pbmp); SOC_PBMP_CLEAR(pkt->tx_upbmp); SOC_PBMP_CLEAR(pkt->tx_l3pbmp); /* get tx_pbmp, tx_upbmp */ eh = (enet_hdr_t *)packet; rv = _socend_l2_lookup(se->se_unit, eh->en_dhost, VLAN_CTRL_ID(se->se_vlan), pkt); if(rv == ERROR){ LOG_CLI((BSL_META("socend_send : can't get egress port(s) by _socend_l2_lookup.\n"))); return(ERROR); } pkt->cookie = cookie; pkt->call_back = socend_send_done; pkt->flags &= ~BCM_TX_CRC_FLD; pkt->flags |= BCM_TX_CRC_APPEND; if ((rv = bcm_tx(se->se_unit, pkt, cookie)) != BCM_E_NONE) { LOG_ERROR(BSL_LS_SOC_COMMON, (BSL_META("bcm_tx failed: Unit %d: %s\n"), se->se_unit, bcm_errmsg(rv))); return(ERROR); } return(OK); }
void socend_receive_netjob(int pi, int pckti, int pckt_size) /* * Function: socend_receive_netjob * Purpose: Called from netjob after packet arrives. * Parameters: p - pointer to (se), cookied passed on registration * pckpi - pointer to packet data (int form). * pckt_size - received length of packet. * Returns: Nothing */ { socend_t *se = (socend_t *)pi; struct end_object *eo = &se->se_eo; void *pckt = (void *)pckti; bcm_vlan_t vid; CL_BLK_ID cb = NULL; M_BLK_ID mb = NULL; /* Check the DCB for errors */ #if defined(BROADCOM_DEBUG) /* Only compile in for debug */ if (LOG_CHECK(BSL_LS_SYS_END | BSL_INFO) && LOG_CHECK(BSL_LS_SOC_PACKET | BSL_INFO)) { d_packet_format("socend RX", DECODE_ETHER, pckt, pckt_size, NULL); } #endif /* BROADCOM_DEBUG */ /* * Build Cluster - then attach to mblks, 1 for each interface that * should get the packet. Broadcast/Multicast packets go up all the stacks. * * For multicast, it should only go up stacks that have registered for that * address, but for now, this will allow multiple interfaces to work. */ if ((NULL == (cb = netClBlkGet(eo->pNetPool, M_DONTWAIT)))) { if (mb) netMblkFree(eo->pNetPool, mb); netClFree(eo->pNetPool, pckt); /* Free packet */ END_ERR_ADD(eo, MIB2_IN_ERRS, +1); return; } #if defined(__mips__) if (SOC_IS_ESW(se->se_unit)) { seu_t *seu = &socend_seu[se->se_unit]; void *tmp; sal_memcpy((UINT8 *)seu->pkt_align_buf + 2, (UINT8 *)pckt, pckt_size); tmp = seu->pkt_align_buf; seu->pkt_align_buf = pckt; pckt = tmp; } #endif /* __mips__ */ /* 1 MBLK for each interface */ if ((mb = mBlkGet(eo->pNetPool, M_DONTWAIT, MT_DATA))) { netClBlkJoin(cb, pckt, SOC_END_PK_SZ, NULL, 0, 0, 0); netMblkClJoin(mb, cb); mb->mBlkPktHdr.len = mb->mBlkHdr.mLen = pckt_size; mb->mBlkHdr.mFlags |= M_PKTHDR; #if defined(__mips__) if (SOC_IS_ESW(se->se_unit)) { mb->mBlkHdr.mData +=2; } #endif /* __mips__ */ vid = VLAN_CTRL_ID(soc_ntohs(((enet_hdr_t *)mb->mBlkHdr.mData)->en_tag_ctrl)); if (SOC_IS_ESW(se->se_unit)) { socend_untag(mb); /* Untag packet for now */ } else { robo_socend_untag(mb); /* Untag packet for now */ } } else { netClBlkFree(eo->pNetPool, cb); netClFree(eo->pNetPool, pckt); /* Free packet */ return; } { M_BLK_ID tmb, fmb = mb; seu_t *seu = &socend_seu[se->se_unit]; /* * Duplicate MBLK, and point to same cluster. */ for (se = seu->seu_devices; se != NULL; se = se->se_next) { if (vid != se->se_vlan) { continue; } eo = &se->se_eo; if (se->se_next != NULL) { tmb = mBlkGet(eo->pNetPool, M_DONTWAIT, MT_DATA); netMblkDup(mb, tmb); } else { fmb = NULL; tmb = mb; } END_RCV_RTN_CALL(eo, tmb); } if (fmb) { netMblkClFree(fmb); } } }