📄 if_sn.c
字号:
/* That was easy. Now we request some memory from the system. * For now, we are taking a simple approach. We simply request one * big region, large enough to ensure that we can position our shared * area in a single 64k page. This approach will waste memory, but * blame the board designers who picked the SONIC without realizing * that the device has this weird restriction. */ if (!CACHE_DMA_IS_WRITE_COHERENT ()) return (ERROR); pDrvCtrl->pMem = cacheDmaMalloc (pDrvCtrl->shMemSize + 0x00010000); if (pDrvCtrl->pMem == NULL) /* no memory, so abort */ return (ERROR); /* Find start of 64k page in the region. This becomes start of our * region. */ pDrvCtrl->pShMem = (char *) (((u_long)pDrvCtrl->pMem & 0xffff0000) + 0x00010000); } /* Block end */ { /***** Carve up the shared area into specific areas *****/ /* Block local variables */ char *pCur; pCur = pDrvCtrl->pShMem; /* start of shared area */ pDrvCtrl->CDA = (u_long) pCur; /* CAM area */ pCur += CAM_SIZE; /* advance the pointer */ pDrvCtrl->RSA = (u_long) pCur; /* receive resource table */ pCur += RRA_SIZE; /* advance the pointer */ pDrvCtrl->REA = (u_long) pCur; /* save end pointer */ pDrvCtrl->RDA = (u_long) pCur; /* receive descriptor area */ pCur += RDA_SIZE; /* advance the pointer */ pDrvCtrl->pTDA = (TX_DESC *)pCur; /* transmit descriptor area */ pCur += TDA_SIZE; /* advance the pointer */ pDrvCtrl->RBA1 = (u_long) pCur; /* Receive Buffer 1 */ pCur += RX_BUF_SIZE + RX_BUF_EXTRA; /* advance the pointer */ pDrvCtrl->RBA2 = (u_long) pCur; /* Receive Buffer 2 */ pCur += RX_BUF_SIZE + RX_BUF_EXTRA; /* advance the pointer */ pDrvCtrl->RBA3 = (u_long) pCur; /* Receive Buffer 3 */ pCur += RX_BUF_SIZE + RX_BUF_EXTRA; /* advance the pointer */ pDrvCtrl->RBA4 = (u_long) pCur; /* Receive Buffer 4 */ } /* Block end */#ifdef SN_DEBUG if (SN_DEBUG_INIT) { /* Dump all the resultant region pointers */ logMsg ("snattach: pDrvCtrl=%x RRA=%x RDA=%x TDA=%x\n", (int)pDrvCtrl, pDrvCtrl->RSA, pDrvCtrl->RDA, (int)pDrvCtrl->pTDA, 0, 0); logMsg ("snattach: RBA1=%x RBA2=%x RBA3=%x RBA4=%x\n", pDrvCtrl->RBA1, pDrvCtrl->RBA2, pDrvCtrl->RBA3, pDrvCtrl->RBA4, 0, 0); }#endif /* SN_DEBUG */ { /***** Perform device initialization *****/ snChipReset (pDrvCtrl); /* reset device */ sysEnetInit (unit); /* do any board specific set up */ sysEnetIntDisable (unit); /* board specific int disable */ /* connect interrupt */ (void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC(ivec),snIntr,unit); { /* init the Tx descriptors */ int loopy; TX_DESC *pTXD; pTXD = pDrvCtrl->pTDA; /* get initial ptr */ bzero ((char *)pTXD, TDA_SIZE); /* zero the whole enchilada */ loopy = NUM_TX_DESC; while (loopy--) /* loop thru each */ { pTXD->pLink = pTXD + 1; /* link to next */ pTXD++; /* bump to next */ } /* The link field of the last desc is special; it needs to point * back to the first desc. So, we fix it here. */ (--pTXD)->pLink = pDrvCtrl->pTDA; pDrvCtrl->pTXDFree = pDrvCtrl->pTDA; /* initial value */ pDrvCtrl->pTXDReclaim = pDrvCtrl->pTDA; /* initial value */ } { /* init the Rx buffer descriptors */ RRA_DESC *pRRAD; /* RRA working descriptor */ /* Build the RRA */ pRRAD = (RRA_DESC *)pDrvCtrl->RSA; /* get ptr to first entry */ /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA1); pRRAD->buff_ptr0 = temp & UMASK; pRRAD->buff_ptr1 = temp >> 16; /* Stuff word count; least significant 16 bits, then most significant 16 */ pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK; pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16; pRRAD++; /* bump to next entry */ /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA2); pRRAD->buff_ptr0 = (u_long) temp & UMASK; pRRAD->buff_ptr1 = (u_long) temp >> 16; /* Stuff word count; least significant 16 bits, then most significant 16 */ pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK; pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16; pRRAD++; /* bump to next entry */ /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA3); pRRAD->buff_ptr0 = (u_long) temp & UMASK; pRRAD->buff_ptr1 = (u_long) temp >> 16; /* Stuff word count; least significant 16 bits, then most significant 16 */ pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK; pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16; pRRAD++; /* bump to next entry */ /* Stuff buffer ptr; least significant 16 bits, then most significant 16 */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RBA4); pRRAD->buff_ptr0 = (u_long) temp & UMASK; pRRAD->buff_ptr1 = (u_long) temp >> 16; /* Stuff word count; least significant 16 bits, then most significant 16 */ pRRAD->buff_wc0 = RX_BUF_SIZE >> 1 & UMASK; pRRAD->buff_wc1 = RX_BUF_SIZE >> 1 >> 16; } { /* Setup the Rx frame descriptors */ RX_DESC *pRXD; /* Rx working descriptor */ pRXD = (RX_DESC *) pDrvCtrl->RDA; /* get initial ptr */ bzero ((char *)pRXD, RDA_SIZE); /* zero the whole tomato */ pDrvCtrl->pRXDNext = pRXD; /* start from the start! */ pDrvCtrl->pRXDLast = /* stuff ptr to last */ (RX_DESC *) ((u_long)pRXD + RDA_SIZE - RX_DESC_SIZ); while (pRXD <= pDrvCtrl->pRXDLast) /* loop thru each */ { pRXD->in_use = NOT_IN_USE; /* set NOT_IN_USE */ pRXD->link = /* set link */ (RX_DESC *) CACHE_DMA_VIRT_TO_PHYS (pRXD + 1); pRXD++; /* bump to next */ } /* The link field of the last desc is special; it points nowhere, * but must mark the end-of-list. So, we fix it here. */ pDrvCtrl->pRXDLast->link = RX_EOL; } /* Enable device interrupts at system level */ sysEnetIntEnable (unit); /* Bring up the device */ snChipInit (pDrvCtrl); } /* Block end */ /* Set flags */ pDrvCtrl->attached = TRUE; pDrvCtrl->sn_ac.ac_if.if_flags |= (IFF_UP | IFF_RUNNING | IFF_NOTRAILERS); return (OK); } /* End of snattach() *//********************************************************************************* snReset - reset the interface** Mark interface as inactive & reset the chip* This is one of the routines that can be called from "outside" via* the interface structure.* Cannot be called before the attach, since DRV_CTRL ptr would be NULL.*/LOCAL void snReset (unit) int unit; { DRV_CTRL *pDrvCtrl;#ifdef SN_DEBUG if (SN_DEBUG_INIT) logMsg ("sn: Reset: unit=%d\n", unit, 0, 0, 0, 0, 0);#endif /* SN_DEBUG */ pDrvCtrl = & drvCtrl [unit]; pDrvCtrl->sn_if.if_flags = 0; snChipReset (pDrvCtrl); /* reset device */ }/********************************************************************************* snChipReset - Place chip in Reset mode*/LOCAL void snChipReset (pDrvCtrl) DRV_CTRL *pDrvCtrl; { pDrvCtrl->pDev->cr = RST; pDrvCtrl->pDev->rsc = 0; /* set the sequence counter to zero */ }/********************************************************************************* snChipInit - hardware init of chip (init & start it)*/LOCAL void snChipInit (pDrvCtrl) DRV_CTRL *pDrvCtrl; { SONIC *pDev; /* ptr to the device regs */ u_long temp; pDev = pDrvCtrl->pDev;#ifdef SN_DEBUG if (SN_DEBUG_INIT) logMsg ("sn: Chip init: pDrvCtrl=0x%X\n", (int)pDrvCtrl, 0, 0, 0, 0, 0);#endif /* SN_DEBUG */ pDev->cr = RST; /* Turn ON RESET */ /* Data Control */ pDev->dcr = snDcr; if (snDcr2) pDev->dcr2 = snDcr2; pDev->imr = 0; /* All Interrupts off */ pDev->isr = 0x7fff; /* Clear ISR */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RSA); pDev->urra = temp >> 16; /* Upper RSA */ pDev->rsa = temp & UMASK; /* Lower RSA */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->REA); pDev->rea = temp & UMASK; /* Lower REA */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RSA); pDev->rrp = temp & UMASK; /* point to first desc */ pDev->rwp = temp & UMASK; /* point to first desc */ pDev->rsc = 0; temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->RDA); pDev->urda = temp >> 16; /* Upper RDA */ pDev->crda = temp & UMASK; /* Lower RDA */ temp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->pTDA); pDev->utda = temp >> 16; /* first TXD */ pDev->ctda = temp & UMASK; pDev->cr = RST_OFF; /* Turn OFF RESET */ pDev->cr = RRRA; /* prime with RRA read */ snCamInit (pDrvCtrl); /* Initialize the CAM */ pDev->rcr = BRD; if (pDev->imr & TCEN) { pDev->wt0 = pDrvCtrl->ticks & 0xffff; pDev->wt1 = pDrvCtrl->ticks >> 16; pDev->cr = ST; } pDev->imr = (pDrvCtrl->imr |= PRXEN); /* Enable these IRQ's */ pDev->cr = RXEN; /* Turn on Receiver */ }/********************************************************************************* snCamInit - put the local Ethernet address in the CAM** First we set up a data area with the enet addr, then we tell the device* where it is and command the device to read it. When the device is done,* it will interrupt us. We wait for this interrupt with a semaphore that* will be given by the interrupt handler.*/LOCAL void snCamInit (pDrvCtrl) DRV_CTRL *pDrvCtrl; { SONIC *pDev; /* ptr to the device regs */ int jj; u_long *CamData; CamData = (unsigned long *) pDrvCtrl->CDA; pDev = pDrvCtrl->pDev; jj = 0; CamData [jj++] = 0; /* Entry 0 */ CamData [jj++] = pDrvCtrl->sn_enaddr [1] << 8 | pDrvCtrl->sn_enaddr [0]; CamData [jj++] = pDrvCtrl->sn_enaddr [3] << 8 | pDrvCtrl->sn_enaddr [2]; CamData [jj++] = pDrvCtrl->sn_enaddr [5] << 8 | pDrvCtrl->sn_enaddr [4]; CamData [jj] = 0x1; /* Enable entry 0 */ pDev->cdc = 1; /* One entry */ pDev->cdp = (u_long) CACHE_DMA_VIRT_TO_PHYS (pDrvCtrl->CDA) & UMASK; pDev->cr = LCAM; /* issue "load CAM" cmd */ /* Wait for operation to complete. A "dead time" loop here is deemed * OK, since we are in initialization phase, and will only do this * once. */ while (!(pDev->isr & LCD)) ; pDev->isr = LCD; /* clear the event flag */ }/********************************************************************************* snIoctl - the driver I/O control function** Process an ioctl request.* This is one of the routines that can be called from "outside" via* the interface structure.* Cannot be called before the attach, since DRV_CTRL ptr would be NULL.*/LOCAL int snIoctl (IDR *pIDR, int cmd, caddr_t data) { int error; error = 0;#ifdef SN_DEBUG if (SN_DEBUG_INIT) logMsg ("sn: Ioctl: pIDR=0x%x, cmd=0x%x, data=0x%x\n", (int)pIDR, (int)cmd, (int)data, 0, 0, 0);#endif /* SN_DEBUG */ switch (cmd) { case SIOCSIFADDR: ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr; arpwhohas (pIDR, &IA_SIN (data)->sin_addr); break; case SIOCSIFFLAGS: /* Flags are set outside this module. No additional work to do. */ break; default: error = EINVAL; } return (error); }/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * SECTION: Transmit related routines *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/#ifdef BSD43_DRIVER/********************************************************************************* snOutput - adds new output to the driver's queue and calls output routine** This is the driver output rotuine. This is one of the routines that is* called from "outside" via the interface structure, ifnet.*/LOCAL int snOutput (pIfnet, pMbuf, pDest) IFNET *pIfnet; MBUF *pMbuf; SOCK *pDest; { DRV_CTRL *pDrvCtrl; int spl; pDrvCtrl = & drvCtrl [pIfnet->if_unit]; spl = splnet (); if (IF_QFULL (&pIfnet->if_snd)) /* If the queue is full */ snStartOutput (pIfnet->if_unit); splx (spl); return (ether_output (pIfnet, pMbuf, pDest, (FUNCPTR) snStartOutput, &pDrvCtrl->sn_ac)); }/*******************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -