📄 if_qu.c
字号:
pDrvCtrl->ether.pSccReg = (SCC_REG *) ((UINT32) M360_CPM_GSMR_L1(quAddr) + (scc * 0x20)); pDrvCtrl->ether.intMask = CPIC_CIXR_SCC4 << (3 - scc); /* set up Rx and Tx buffers */ if (bufBase == NONE) { /* allocate memory pools */ txBuf = cacheDmaMalloc (txBdNum * pDrvCtrl->ether.txBufSize); if (txBuf == NULL) return (ERROR); rxBuf = cacheDmaMalloc (rxBdNum * pDrvCtrl->ether.rxBufSize); if (rxBuf == NULL) { free (txBuf); return (ERROR); } loanBuf = cacheDmaMalloc (loanNum * pDrvCtrl->ether.rxBufSize); if (loanBuf == NULL) pDrvCtrl->nLoanRxBd = 0; } else { /* use passed in address as memory pool - assume OK */ txBuf = (u_char *) bufBase; rxBuf = (u_char *) (txBuf + (txBdNum * pDrvCtrl->ether.txBufSize)); loanBuf = (u_char *) (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 */ quReset (unit); /* connect the interrupt handler quIntr() */ if (intConnect (INUM_TO_IVEC (ivec), (VOIDFUNCPTR) quIntr, unit) == ERROR) return (ERROR); quInit (unit); /* mark driver as attached */ pDrvCtrl->attached = TRUE; return (OK); }/********************************************************************************* quInit - 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.** This routine is called from the driver attach routine at boot time.** The complement of this rotuine is quReset(). Once a unit is reset by* quReset(), it may be re-initialized to a running state by this routine.** RETURNS: OK if successful, otherwise ERROR.*/LOCAL STATUS quInit ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl; u_char enetAddr[ENET_ADDR_SIZE]; int counter; /* sanity check the unit number */ if (unit < 0 || unit >= MAX_UNITS) return (ERROR); pDrvCtrl = & drvCtrl[unit]; /* ensure single invocation */ if (pDrvCtrl->initialized) return (OK); /* 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 (sys360EnetAddrGet (unit, (u_char *) & 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; *M360_CPM_CIMR(pDrvCtrl->regBase) |= pDrvCtrl->ether.intMask; /* call the BSP to do any other initialization (e.g., connecting clocks) */ if (sys360EnetEnable (unit, pDrvCtrl->regBase) == ERROR) return (ERROR); /* raise the interface flags - mark the device as up */ pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS; /* mark driver as initialized */ pDrvCtrl->initialized = TRUE; /* enable the transmitter */ pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENT; /* issue the restart transmitter command to the CP */ while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); *M360_CPM_CR(pDrvCtrl->regBase) = ((pDrvCtrl->ether.sccNum - 1) << 6) | CPM_CR_SCC_RESTART | CPM_CR_FLG; while (*M360_CPM_CR(pDrvCtrl->regBase) & CPM_CR_FLG); /* enable the receiver */ pDrvCtrl->ether.pSccReg->gsmrl |= SCC_GSMRL_ENR; return (OK); }#ifdef BSD43_DRIVER/********************************************************************************* quOutput - network interface output routine** This routine simply calls ether_output(). ether_output() resolves * the hardware addresses and calls quStartOutput() with the unit number* passed as an argument.** RETURNS: OK if successful, otherwise errno.*/LOCAL int quOutput ( 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) quStartOutput, & pDrvCtrl->idr)); }/********************************************************************************* quStartOutput - output packet to network interface device** quStartOutput() 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. This will cause quOutput() 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 case, the outgoing data will be thrown out (very rare case).** 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 quTxRestart() routine. After the transmitter is restarted,* quTxRestart() does a netJobAdd of quStartOutput() 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 quStartOutput() to continue sending* packets left in the interface output queue. Once again, we find ourselves* executing in the context of netTask().** RETURNS: N/A*/LOCAL void quStartOutput ( int unit /* unit number */ ) { DRV_CTRL * pDrvCtrl = & drvCtrl[unit];#else /* BSD43_DRIVER */LOCAL void quStartOutput ( DRV_CTRL * pDrvCtrl /* unit number */ ) {#endif /* BSD43_DRIVER */ MBUF * pMbuf; /* mbuf pointer */ int length; SCC_BUF * pTxBd; u_char * 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); /* QUICC 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; } } }/********************************************************************************* quIoctl - 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 quIoctl ( 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 ((struct arpcom *)pIfNet, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -