📄 amd79c970.c
字号:
/* * COPYRIGHT (c) 1998 by Radstone Technology * * * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU. * * You are hereby granted permission to use, copy, modify, and distribute * this file, provided that this notice, plus the above copyright notice * and disclaimer, appears in all copies. Radstone Technology will provide * no support for this code. * *//* * RTEMS/KA9Q driver for PC-NET */#include <bsp.h>#include <rtems/error.h>#include <ka9q/rtems_ka9q.h>#include <ka9q/global.h>#include <ka9q/enet.h>#include <ka9q/iface.h>#include <ka9q/netuser.h>#include <ka9q/trace.h>#include <ka9q/commands.h>#include <pci.h>#include "amd79c970.h"/* * Number of PC-NETs supported by this driver */#define NPCNETDRIVER 1/* * Default number of buffer descriptors set aside for this driver. * The number of transmit buffer descriptors has to be quite large * since a single frame often uses four or more buffer descriptors. * * Set the number of Tx and Rx buffers, using Log_2(# buffers). */#define LANCE_LOG2_TX_BUFFERS 4#define LANCE_LOG2_RX_BUFFERS 4#define TX_RING_SIZE (1 << (LANCE_LOG2_TX_BUFFERS))#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)#define TX_RING_LEN_BITS ((LANCE_LOG2_TX_BUFFERS) << 4)#define RX_RING_SIZE (1 << (LANCE_LOG2_RX_BUFFERS))#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)#define RX_RING_LEN_BITS ((LANCE_LOG2_RX_BUFFERS) << 4)/* * RTEMS event used by interrupt handler to signal daemons. * This must *not* be the same event used by the KA9Q task synchronization. */#define INTERRUPT_EVENT RTEMS_EVENT_1/* * Receive buffer size -- Allow for a full ethernet packet plus a pointer */#define ETHPKT_SIZE 1520#define RBUF_SIZE (ETHPKT_SIZE + sizeof (struct iface *))/* * LANCE Register Access Macros */#define PCNET_IO_RD32(dp, reg, value) \ inport_32(&dp->pPCNet->u.dwio.##reg, value)#define PCNET_IO_WR32(dp, reg, value) \ outport_32(&dp->pPCNet->u.dwio.##reg, value)/* * LANCE Register Access Macros */#define RD_CSR32(dp, index, value) \ PCNET_IO_WR32(dp, rap, index); \ PCNET_IO_RD32(dp, rdp, value) #define WR_CSR32(dp, index, value) \ PCNET_IO_WR32(dp, rap, index); \ PCNET_IO_WR32(dp, rdp, value) #define RD_BCR32(dp, index, value) \ PCNET_IO_WR32(dp, rap, index); \ PCNET_IO_RD32(dp, bdp, value)#define WR_BCR32(dp, index, value) \ PCNET_IO_WR32(dp, rap, index); \ PCNET_IO_WR32(dp, bdp, value)/* * Hardware-specific storage * * Note that the enetInitBlk field must be aligned to a 16 byte * boundary */typedef struct amd79c970Context { rmde_t rxBdBase[RX_RING_SIZE]; tmde_t txBdBase[TX_RING_SIZE]; initblk_t initBlk; pc_net_t *pPCNet; unsigned32 ulIntVector; struct mbuf **rxMbuf; struct mbuf **txMbuf; int rxBdCount; int txBdCount; int txBdHead; int txBdTail; int txBdActiveCount; struct iface *iface; rtems_id txWaitTid; /* * Statistics */ unsigned long rxInterrupts; unsigned long rxNotFirst; unsigned long rxNotLast; unsigned long rxGiant; unsigned long rxNonOctet; unsigned long rxRunt; unsigned long rxBadCRC; unsigned long rxOverrun; unsigned long rxCollision; unsigned long rxDiscarded; unsigned long txInterrupts; unsigned long txDeferred; unsigned long txHeartbeat; unsigned long txLateCollision; unsigned long txRetryLimit; unsigned long txUnderrun; unsigned long txLostCarrier; unsigned long txRawWait;} amd79c970Context_t;static amd79c970Context_t *pAmd79c970Context[NPCNETDRIVER];/* * PC-NET interrupt handler */static rtems_isramd79c970_isr (rtems_vector_number v){ unsigned32 ulCSR0, ulCSR4, ulCSR5; amd79c970Context_t *dp; int i; for(i=0; i<NPCNETDRIVER; i++) { dp=pAmd79c970Context[i]; if(dp->ulIntVector==v) { RD_CSR32(dp, CSR0, ulCSR0); if(ulCSR0 & CSR0_RINT) { /* * We have recieve data */ dp->rxInterrupts++; rtems_event_send( dp->iface->rxproc, INTERRUPT_EVENT); } if(ulCSR0 & CSR0_TINT) { /* * Data tranmitted or error */ dp->txInterrupts++; if(dp->txWaitTid) { rtems_event_send( dp->txWaitTid, INTERRUPT_EVENT); } } if((ulCSR0 & CSR0_INTR) && !(ulCSR0 & (CSR0_RINT | CSR0_TINT))) { /* * Many possible sources */ RD_CSR32(dp, CSR4, ulCSR4); RD_CSR32(dp, CSR5, ulCSR5); DEBUG_puts("CSR0="); DEBUG_puth(ulCSR0); DEBUG_puts(", CSR4="); DEBUG_puth(ulCSR4); DEBUG_puts(", CSR5="); DEBUG_puth(ulCSR5); DEBUG_puts("\n\r"); /* * Clear it */ WR_CSR32(dp, CSR4, ulCSR4); WR_CSR32(dp, CSR5, ulCSR5); } /* * Clear interrupts */ ulCSR0&=CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR | CSR0_RINT | CSR0_TINT | CSR0_IENA; WR_CSR32(dp, CSR0, ulCSR0); RD_CSR32(dp, CSR0, ulCSR0); } }}/* * Initialize the ethernet hardware */static booleanamd79c970_initialize_hardware (int instance, int broadcastFlag){ amd79c970Context_t *dp; struct mbuf *bp; int i; unsigned8 ucPCIBusCount; unsigned8 ucBusNumber; unsigned8 ucSlotNumber; unsigned32 ulDeviceID; unsigned32 ulBAR0; unsigned8 ucIntVector; unsigned32 ulInitClkPCIAddr; unsigned32 ulAPROM; unsigned32 ulCSR0; ucPCIBusCount=BusCountPCI(); /* * Scan the available busses for instance of hardware */ i=0; dp=pAmd79c970Context[instance]; dp->pPCNet=(pc_net_t *)NULL; for(ucBusNumber=0; (ucBusNumber<ucPCIBusCount) && (dp->pPCNet==(pc_net_t *)NULL); ucBusNumber++) { for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) { PCIConfigRead32(ucBusNumber, ucSlotNumber, 0, PCI_CONFIG_VENDOR_LOW, &ulDeviceID); if(ulDeviceID!=PCI_ID(0x1022, 0x2000)) { continue; } /* * We've found a PC-NET controller */ if(i++<instance) { continue; } /* * Read base address */ PCIConfigRead32(ucBusNumber, ucSlotNumber, 0, PCI_CONFIG_BAR_0, &ulBAR0); dp->pPCNet=(pc_net_t *)(ulBAR0&~PCI_ADDRESS_IO_SPACE); /* * Read interrupt vector */ PCIConfigRead8(ucBusNumber, ucSlotNumber, 0, PCI_CONFIG_INTERRUPTLINE, &ucIntVector); dp->ulIntVector=PPCN_60X_IRQ_PCI(ucIntVector); /* * Ensure that device is enabled */ PCIConfigWrite16(ucBusNumber, ucSlotNumber, 0, PCI_CONFIG_COMMAND, PCI_ENABLE_IO_SPACE | PCI_ENABLE_BUS_MASTER); break; } } if(dp->pPCNet==(pc_net_t *)NULL) { return(FALSE); } /* * Read the ethernet number */ if(!dp->iface->hwaddr) { dp->iface->hwaddr=mallocw (EADDR_LEN); PCNET_IO_RD32(dp, aprom[0], ulAPROM); for(i=0;i<4;i++) { dp->iface->hwaddr[i]=(ulAPROM>>(i*8))&0xff; } PCNET_IO_RD32(dp, aprom[1], ulAPROM); for(i=0;i<2;i++) { dp->iface->hwaddr[i+4]=(ulAPROM>>(i*8))&0xff; } } /* * Allocate mbuf pointers */ dp->rxMbuf=mallocw (dp->rxBdCount * sizeof(*dp->rxMbuf)); dp->txMbuf=mallocw (dp->txBdCount * sizeof(*dp->txMbuf)); /* * Allocate space for incoming packets */ for(i=0; i<dp->rxBdCount; i++) { dp->rxMbuf[i]=bp=ambufw (RBUF_SIZE); bp->data += sizeof (struct iface *); dp->rxBdBase[i].rmde_addr= Swap32((unsigned32)bp->data+PCI_SYS_MEM_BASE); dp->rxBdBase[i].rmde_bcnt= Swap16(-(bp->size-sizeof (struct iface *))); dp->rxBdBase[i].rmde_flags=Swap16(RFLG_OWN); } /* * Set up transmit buffer descriptors */ for(i=0; i<dp->txBdCount; i++) { dp->txBdBase[i].tmde_status=Swap16(TST_STP | TST_ENP); dp->txBdBase[i].tmde_error=0; dp->txMbuf[i]=NULL; } /* * Initialise initblk */ if(broadcastFlag) { dp->initBlk.ib_mode=0; } else { dp->initBlk.ib_mode=Swap16(CSR15_DRCVBC); } /* * Set the receive descriptor ring length */ dp->initBlk.ib_rlen=RX_RING_LEN_BITS; /* * Set the receive descriptor ring address */ dp->initBlk.ib_rdra=Swap32((unsigned32)&dp->rxBdBase[0]+ PCI_SYS_MEM_BASE); /* * Set the transmit descriptor ring length */ dp->initBlk.ib_tlen=TX_RING_LEN_BITS; /* * Set the tranmit descriptor ring address */ dp->initBlk.ib_tdra=Swap32((unsigned32)&dp->txBdBase[0]+ PCI_SYS_MEM_BASE); for(i=0;i<6;i++) { dp->initBlk.ib_padr[i]=dp->iface->hwaddr[i]; } /* * Ensure that we are in DWIO mode */ PCNET_IO_WR32(dp, rdp, 0); WR_CSR32(dp, 58,CSR58_PCISTYLE); WR_CSR32(dp, CSR3, CSR3_BABLM | CSR3_MERRM | CSR3_IDONM | CSR3_DXSUFLO); WR_CSR32(dp, CSR4, CSR4_APADXMIT | CSR4_MFCOM | CSR4_RCVCCOM | CSR4_TXSTRTM | CSR4_JABM); WR_CSR32(dp, CSR5, 0); ulInitClkPCIAddr=(unsigned32)&dp->initBlk+PCI_SYS_MEM_BASE; /* * CSR2 must contain the high order 16 bits of the first word in * the initialization block */ WR_CSR32(dp, CSR2, (ulInitClkPCIAddr >> 16) & 0xffff); /* * CSR1 must contain the low order 16 bits of the first word in * the initialization block */ WR_CSR32(dp, CSR1, (ulInitClkPCIAddr & 0xffff)); /* * Set up interrupts */ set_vector(amd79c970_isr, dp->ulIntVector, instance); /* * Start the device */ WR_CSR32(dp, CSR0, CSR0_INIT | CSR0_STRT); /* * Wait for 100mS for the device to initialise */ for(i=0; i<100; i++) { RD_CSR32(dp, CSR0, ulCSR0); if(ulCSR0 & CSR0_IDON) { break; } rtems_ka9q_ppause(1); /* 1mS */ } if(i >= 100) { return(FALSE); } /* * Enable interrupts */ WR_CSR32(dp, CSR0, CSR0_IENA); dp->txBdHead=dp->txBdTail=0; dp->txBdActiveCount=0; return(TRUE);}/* * Soak up buffer descriptors that have been sent */static voidamd79c970_retire_tx_bd (amd79c970Context_t *dp){ unsigned16 status; unsigned32 error; int i; int nRetired; i = dp->txBdTail; nRetired = 0; while((dp->txBdActiveCount != 0) && (((status=Swap16(dp->txBdBase[i].tmde_status)) & TST_OWN)==0)) { /* * See if anything went wrong */ if(status & TST_ERR) { /* * Check for errors */ error=Swap16(dp->txBdBase[i].tmde_error); if (error & TERR_LCOL) dp->txLateCollision++; if (error & TERR_RTRY) dp->txRetryLimit++; if (error & TERR_UFLO) dp->txUnderrun++; if (error & TERR_EXDEF) dp->txDeferred++; if (error & TERR_LCAR) dp->txLostCarrier++; } nRetired++; if (status & TST_ENP) { /* * A full frame has been transmitted. * Free all the associated buffer descriptors. */ dp->txBdActiveCount -= nRetired; while (nRetired) { nRetired--; free_mbuf (&dp->txMbuf[dp->txBdTail]); if (++dp->txBdTail == dp->txBdCount)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -