📄 if_cpm.c
字号:
loanBuf = cacheDmaMalloc (loanNum * pDrvCtrl->ether.rxBufSize); if (loanBuf == NULL) pDrvCtrl->nLoanRxBd = 0; } else { /* use passed in address as memory pool - assume OK */ txBuf = bufBase; rxBuf = (UINT8 *) (txBuf + (txBdNum * pDrvCtrl->ether.txBufSize)); loanBuf = (UINT8 *) (rxBuf + (rxBdNum * pDrvCtrl->ether.rxBufSize)); } /* assign buffer addresses */ for (counter = 0; counter < txBdNum; counter++) pDrvCtrl->ether.txBdBase[counter].dataPointer = (txBuf + (counter * pDrvCtrl->ether.txBufSize)); for (counter = 0; counter < rxBdNum; counter++) pDrvCtrl->ether.rxBdBase[counter].dataPointer = (rxBuf + (counter * pDrvCtrl->ether.rxBufSize)); for (counter = 0; counter < pDrvCtrl->nLoanRxBd; counter++) { pDrvCtrl->lPool[counter] = (loanBuf + (counter * pDrvCtrl->ether.rxBufSize)); pDrvCtrl->refCnt[counter] = 0; pDrvCtrl->pRefCnt[counter] = & pDrvCtrl->refCnt[counter]; } /* reset the chip */ if (cpmReset (unit) == ERROR) return (ERROR); /* connect the interrupt handler cpmIntr() */ if (intConnect (ivec, (VOIDFUNCPTR) cpmIntr, unit) == ERROR) return (ERROR); /* Initialize and start controller */ cpmInit (unit); /* mark driver as attached */ pDrvCtrl->attached = TRUE; return (OK); }/********************************************************************************* cpmInit - network interface initialization routine** This routine marks the interface as down, then configures and initializes* the chip. It sets up the transmit and receive buffer descriptor (BD)* rings, initializes registers, and enables interrupts. Finally, it marks* the interface as up and running. It does not touch the receive loaner* buffer stack.** The complement of this routine is cpmReset(). Once a unit is reset by* cpmReset(), it may be re-initialized to a running state by this routine.** RETURNS: OK if successful, otherwise ERROR.*/LOCAL STATUS cpmInit ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; UINT8 enetAddr[ENET_ADDR_SIZE]; int counter; /* sanity check the unit number */ if (unit < 0 || unit >= MAX_UNITS) return (ERROR); pDrvCtrl = & drvCtrl[unit]; /* mark the device as down */ pDrvCtrl->idr.ac_if.if_flags &= ~(IFF_UP | IFF_RUNNING); /* initialize flag(s) */ pDrvCtrl->txStop = FALSE; /* set up transmit buffer descriptors */ pDrvCtrl->ether.pScc->param.tbase = (UINT16) ((UINT32) pDrvCtrl->ether.txBdBase & 0xfff); pDrvCtrl->ether.pScc->param.tbptr = (UINT16) ((UINT32) pDrvCtrl->ether.txBdBase & 0xfff); pDrvCtrl->ether.txBdNext = 0; /* initialize each transmit buffer descriptor */ for (counter = 0; counter < pDrvCtrl->ether.txBdNum; counter++) pDrvCtrl->ether.txBdBase[counter].statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC; /* set the last BD to wrap to the first */ pDrvCtrl->ether.txBdBase[(counter - 1)].statusMode |= SCC_ETHER_TX_BD_W; /* set up receive buffer descriptors */ pDrvCtrl->ether.pScc->param.rbase = (UINT16) ((UINT32) pDrvCtrl->ether.rxBdBase & 0xfff); pDrvCtrl->ether.pScc->param.rbptr = (UINT16) ((UINT32) pDrvCtrl->ether.rxBdBase & 0xfff); pDrvCtrl->ether.rxBdNext = 0; /* initialize each receive buffer descriptor */ for (counter = 0; counter < pDrvCtrl->ether.rxBdNum; counter++) pDrvCtrl->ether.rxBdBase[counter].statusMode = SCC_ETHER_RX_BD_I | SCC_ETHER_RX_BD_E; /* set the last BD to wrap to the first */ pDrvCtrl->ether.rxBdBase[(counter - 1)].statusMode |= SCC_ETHER_RX_BD_W; /* set SCC attributes to Ethernet mode */ pDrvCtrl->ether.pSccReg->gsmrl = SCC_GSMRL_ETHERNET | SCC_GSMRL_TPP_10 | SCC_GSMRL_TPL_48 | SCC_GSMRL_TCI; pDrvCtrl->ether.pSccReg->gsmrh = 0x0; pDrvCtrl->ether.pSccReg->psmr = SCC_ETHER_PSMR_CRC | SCC_ETHER_PSMR_NIB_22; if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO; pDrvCtrl->ether.pSccReg->dsr = 0xd555; pDrvCtrl->ether.pScc->param.rfcr = 0x18; /* supervisor data access */ pDrvCtrl->ether.pScc->param.tfcr = 0x18; /* supervisor data access */ pDrvCtrl->ether.pScc->param.mrblr = FRAME_MAX_AL; /* max rx buffer size */ /* initialize parameter the SCC RAM */ ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_pres = 0xffffffff; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->c_mask = 0xdebb20e3; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->crcec = 0x00000000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->alec = 0x00000000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->disfc = 0x00000000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->pads = 0x8888; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->ret_lim = 0x000f; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->mflr = FRAME_MAX; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->minflr = FRAME_MIN; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd1 = FRAME_MAX; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->maxd2 = FRAME_MAX; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr1 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr2 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr3 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->gaddr4 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->p_per = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr1 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr2 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr3 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->iaddr4 = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_h = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_m = 0x0000; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->taddr_l = 0x0000; /* set the hardware Ethernet address of the board */ if (sysCpmEnetAddrGet (unit, (UINT8 *) & enetAddr) == ERROR) return (ERROR); ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_h = (enetAddr[5] << 8) + enetAddr[4]; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_m = (enetAddr[3] << 8) + enetAddr[2]; ((SCC_ETHER_PROTO *)pDrvCtrl->ether.pScc->prot)->paddr1_l = (enetAddr[1] << 8) + enetAddr[0]; bcopy ((char *) enetAddr, (char *) pDrvCtrl->idr.ac_enaddr, ENET_ADDR_SIZE); /* enable Ethernet interrupts */ pDrvCtrl->ether.pSccReg->scce = 0xffff; /* clr events */ pDrvCtrl->ether.pSccReg->sccm = SCC_ETHER_SCCX_RXF | SCC_ETHER_SCCX_TXE; sysCpmEnetIntEnable (unit); /* unmask interrupts */ /* call the BSP to do any other initialization (e.g., connecting clocks) */ if (sysCpmEnetEnable (unit) == ERROR) return (ERROR); /* raise the interface flags - mark the device as up */ pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS; /* enable the transmitter */ pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT; /* issue the restart transmitter command to the CP */ (void) sysCpmEnetCommand (unit, CPM_CR_SCC_RESTART); /* enable the receiver */ pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR; return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* cpmOutput - network interface output routine** This routine simply calls ether_output(). ether_output() resolves * the hardware addresses and calls cpmStartOutput() with the unit number* passed as an argument.** RETURNS: OK if successful, otherwise errno.*/LOCAL int cpmOutput ( IFNET * pIfNet, /* pointer to IFNET structure */ MBUF * pMbuf, /* mbuf chain for output */ SOCK * pSock /* sock ptr for destination */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit]; return (ether_output (pIfNet, pMbuf, pSock, (FUNCPTR) cpmStartOutput, & pDrvCtrl->idr)); }#endif/********************************************************************************* cpmStartOutput - output packet to network interface device** cpmStartOutput() takes a packet from the network interface output queue,* copies the mbuf chain into an interface buffer, and sends the packet over* the interface. etherOutputHookRtns are supported.** Collision stats are collected in this routine from previously sent BDs.* These BDs will not be examined until after the transmitter has cycled the* ring, coming upon the BD after it has been sent. Thus, collision stat* collection will be delayed a full cycle through the Tx ring.** This routine is called from several possible threads. Each one will be* described below.** The first, and most common thread, is when a user task requests the* transmission of data. Under BSD 4.3, this will cause cpmOutput() to be* called, which calls ether_output(), which usually calls this routine. * This routine will not be called if ether_output() finds that our interface* output queue is full. In this very rare case, the outgoing data will be * thrown out. BSD 4.4 uses a slightly different model in which the generic* ether_output() routine is called directly, followed by a call to this* routine.** The second thread is when a transmitter error occurs that causes a* TXE event interrupt. This happens for the following errors: transmitter* underrun, retry limit reached, late collision, and heartbeat error.* The ISR sets the txStop flag to stop the transmitter until the errors are* serviced. These events require a RESTART command of the transmitter, which* occurs in the cpmTxRestart() routine. After the transmitter is restarted,* cpmTxRestart() does a netJobAdd of cpmStartOutput() to send any packets* left in the interface output queue. Thus, the second thread executes* in the context of netTask().** The third, and most unlikely, thread occurs when this routine is executing* and it runs out of free Tx BDs. In this case, this routine turns on* transmit interrupt and exits. When the next BD is actually sent, an interrupt* occurs. The ISR does a netJobAdd of cpmStartOutput() to continue sending* packets left in the interface output queue. Once again, we find ourselves* executing in the context of netTask().** RETURNS: N/A*/#ifdef BSD43_DRIVERLOCAL void cpmStartOutput ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit];#elseLOCAL void cpmStartOutput ( DRV_CTRL * pDrvCtrl /* driver control structure */ ) {#endif MBUF * pMbuf; /* mbuf pointer */ int length; SCC_BUF * pTxBd; UINT8 * pad; /* * Loop until: * a) there are no more packets ready to send * b) we have insufficient resources left to send another one * c) a fatal transmitter error occurred, thus txStop was set */ while (!pDrvCtrl->txStop && (pDrvCtrl->idr.ac_if.if_snd.ifq_head != NULL)) { pTxBd = & pDrvCtrl->ether.txBdBase[pDrvCtrl->ether.txBdNext]; /* check if a transmit buffer descriptor is available */ if (pTxBd->statusMode & SCC_ETHER_TX_BD_R) { /* if no BD available, enable interrupt to see when one is free */ pDrvCtrl->ether.pSccReg->scce = SCC_ETHER_SCCX_TXB; pDrvCtrl->ether.pSccReg->sccm |= SCC_ETHER_SCCX_TXB; break; } IF_DEQUEUE (& pDrvCtrl->idr.ac_if.if_snd, pMbuf); /* dequeue a packet */ copy_from_mbufs (pTxBd->dataPointer, pMbuf, length); /* padding mechanism in Rev A is buggy - do in software */ if (length < FRAME_MIN) { pad = pTxBd->dataPointer + length; for (; length != FRAME_MIN; length++, pad++) *pad = 0x88; } /* call hook if one is connected */ if ((etherOutputHookRtn == NULL) || ((* etherOutputHookRtn) (& pDrvCtrl->idr.ac_if, pTxBd->dataPointer, length) == 0)) { /* add in collision stats from previously sent BDs */ pDrvCtrl->idr.ac_if.if_collisions += ((pTxBd->statusMode & SCC_ETHER_TX_BD_RC) >> 2); /* if hook did not grab the frame, send packet */ pTxBd->dataLength = length; if (pTxBd->statusMode & SCC_ETHER_TX_BD_W) pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC | SCC_ETHER_TX_BD_W | SCC_ETHER_TX_BD_R; else pTxBd->statusMode = SCC_ETHER_TX_BD_I | SCC_ETHER_TX_BD_PAD | SCC_ETHER_TX_BD_L | SCC_ETHER_TX_BD_TC | SCC_ETHER_TX_BD_R; /* incr BD count */ pDrvCtrl->ether.txBdNext = (pDrvCtrl->ether.txBdNext + 1) % pDrvCtrl->ether.txBdNum;#ifndef BSD43_DRIVER /* BSD 4.4 ether_output() doesn't bump statistic. */ pDrvCtrl->idr.ac_if.if_opackets++;#endif } } }/********************************************************************************* cpmIoctl - network interface control routine** This routine implements the network interface control functions.* It handles SIOCSIFADDR and SIOCSIFFLAGS commands.** RETURNS: OK if successful, otherwise EINVAL.*/LOCAL int cpmIoctl ( IFNET * pIfNet, /* pointer to IFNET structure */ int cmd, /* command to process */ caddr_t data /* pointer to data */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[pIfNet->if_unit]; int error = 0; /* error value */ int s = splimp (); /* sem not taken in calling functions */ switch (cmd) { case SIOCSIFADDR: /* set interface address */ ((struct arpcom *)pIfNet)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIfNet, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* set promiscuous bit according to flags */ if (pDrvCtrl->idr.ac_if.if_flags & IFF_PROMISC) pDrvCtrl->ether.pSccReg->psmr |= SCC_ETHER_PSMR_PRO; else pDrvCtrl->ether.pSccReg->psmr &= ~SCC_ETHER_PSMR_PRO; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -