From 9916cec6ae06313c014936562cc34e8c6ffb1137 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 1 Apr 2013 23:17:47 +0800 Subject: [PATCH] Kernel/Modules - Heaps of work on PCnet FASTIII driver --- .../Modules/Network/PCnet-FASTIII/Makefile | 7 - .../Network/PCnet-FASTIII/pcnet-fast3.c | 386 ------------- .../Modules/Network/PCnetFAST3/Makefile | 7 + KernelLand/Modules/Network/PCnetFAST3/hw.h | 98 ++++ .../Modules/Network/PCnetFAST3/pcnet-fast3.c | 523 ++++++++++++++++++ 5 files changed, 628 insertions(+), 393 deletions(-) delete mode 100644 KernelLand/Modules/Network/PCnet-FASTIII/Makefile delete mode 100644 KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c create mode 100644 KernelLand/Modules/Network/PCnetFAST3/Makefile create mode 100644 KernelLand/Modules/Network/PCnetFAST3/hw.h create mode 100644 KernelLand/Modules/Network/PCnetFAST3/pcnet-fast3.c diff --git a/KernelLand/Modules/Network/PCnet-FASTIII/Makefile b/KernelLand/Modules/Network/PCnet-FASTIII/Makefile deleted file mode 100644 index 1c7f3e94..00000000 --- a/KernelLand/Modules/Network/PCnet-FASTIII/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# - -OBJ = rtl8139.o -NAME = RTL8139 - --include ../Makefile.tpl diff --git a/KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c b/KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c deleted file mode 100644 index bb4f83a8..00000000 --- a/KernelLand/Modules/Network/PCnet-FASTIII/pcnet-fast3.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Acess2 PCnet-FAST III Driver - * - By John Hodge (thePowersGang) - */ -#define DEBUG 0 -#define VERSION ((0<<8)|10) -#include -#include -#include -#include -#include -#include - -// === CONSTANTS === -#define VENDOR_ID 0x1022 -#define DEVICE_ID 0x2000 - -enum eRegs -{ - REG_APROM0 = 0x00, - REG_APROM4 = 0x04, - REG_APROM8 = 0x08, - REG_APROMC = 0x0C, - REG_RDP = 0x10, // 16 bit - REG_RAP = 0x14, // 8-bit - REG_RESET = 0x18, // 16-bit - REG_BDP = 0x1C, // 16-bit -}; - -enum eCSR_Regs -{ - CSR_STATUS, // CSR0 - Am79C973/Am79C975 Controller Status - CSR_IBA0, // CSR1 - Initialization Block Address[15:0] - CSR_IBA1, // CSR2 - Initialization Block Address[31:16] - CSR_INTMASK, // CSR3 - Interrupt Masks and Deferral Control - - CSR_MAC0 = 12, // CSR12 - Physical Address[15:0] - CSR_MAC1 = 13, // CSR13 - Physical Address[31:16] - CSR_MAC2 = 14, // CSR14 - Physical Address[47:32] - CSR_MODE = 15, // CSR15 - Mode - - CSR_RXBASE0 = 24, // CSR24 - Base Address of Receive Ring Lower - CSR_RXBASE1 = 25, // CSR25 - Base Address of Receive Ring Upper - CSR_TXBASE0 = 30, // CSR26 - Base Address of Transmit Ring Lower - CSR_TXBASE1 = 31, // CSR27 - Base Address of Transmit Ring Upper - - CSR_RXLENGTH = 76, // CSR76 - Receive Ring Length - CSR_TXLENGTH = 78, // CSR78 - Transmit Ring Length -}; - -enum eBCR_Regs -{ - BCR_PHYCS = 32, // BCR32 - Internal PHY Control and Status - BCR_PHYADDR, // BCR33 - Internal PHY Address - BCR_PHYMGMT, // BCR34 - Internal PHY Management Data -}; - -// === TYPES === -typedef struct sCard -{ - Uint16 IOBase; - Uint8 IRQ; - - int NumWaitingPackets; - - char Name[2]; - tVFS_Node Node; - Uint8 MacAddr[6]; -} tCard; - -// === PROTOTYPES === - int PCnet3_Install(char **Options); -char *PCnet3_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *PCnet3_FindDir(tVFS_Node *Node, const char *Filename); - int PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Arg); -Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); -Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); - int PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Arg); -void PCnet3_IRQHandler(int Num); - -// === GLOBALS === -MODULE_DEFINE(0, VERSION, PCnet3, PCnet3_Install, NULL, NULL); -tDevFS_Driver gPCnet3_DriverInfo = { - NULL, "PCnet3", - { - .NumACLs = 1, - .ACLs = &gVFS_ACL_EveryoneRX, - .Flags = VFS_FFLAG_DIRECTORY, - .ReadDir = PCnet3_ReadDir, - .FindDir = PCnet3_FindDir, - .IOCtl = PCnet3_RootIOCtl - } -}; - int giPCnet3_CardCount; -tCard *gaPCnet3_Cards; - -// === CODE === -/** - * \brief Installs the PCnet3 Driver - */ -int PCnet3_Install(char **Options) -{ - int id = -1; - int i = 0; - Uint16 base; - tCard *card; - - giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID); - Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount); - - if( giPCnet3_CardCount == 0 ) return MODULE_ERR_NOTNEEDED; - - gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) ); - - while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 ) - { - card = &gaPCnet3_Cards[i]; - base = PCI_GetBAR( id, 0 ); - if( !(base & 1) ) { - Log_Warning("PCnet3", "Driver does not support MMIO, skipping card"); - card->IOBase = 0; - card->IRQ = 0; - continue ; - } - base &= ~1; - card->IOBase = base; - card->IRQ = PCI_GetIRQ( id ); - - // Install IRQ Handler - IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler); - - - - Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x", - i, card->IOBase, card->IRQ, - card->MacAddr[0], card->MacAddr[1], card->MacAddr[2], - card->MacAddr[3], card->MacAddr[4], card->MacAddr[5] - ); - - i ++; - } - - gPCnet3_DriverInfo.RootNode.Size = giPCnet3_CardCount; - DevFS_AddDevice( &gPCnet3_DriverInfo ); - - return MODULE_ERR_OK; -} - -// --- Root Functions --- -char *PCnet3_ReadDir(tVFS_Node *Node, int Pos) -{ - if( Pos < 0 || Pos >= giPCnet3_CardCount ) return NULL; - - return strdup( gaPCnet3_Cards[Pos].Name ); -} - -tVFS_Node *PCnet3_FindDir(tVFS_Node *Node, const char *Filename) -{ - //TODO: It might be an idea to supprt >10 cards - if(Filename[0] == '\0' || Filename[1] != '\0') return NULL; - if(Filename[0] < '0' || Filename[0] > '9') return NULL; - return &gaPCnet3_Cards[ Filename[0]-'0' ].Node; -} - -const char *csaPCnet3_RootIOCtls[] = {DRV_IOCTLNAMES, NULL}; -int PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Data) -{ - ENTER("pNode iID pData", Node, ID, Data); - switch(ID) - { - BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_RootIOCtls); - } - LEAVE('i', 0); - return 0; -} - -// --- File Functions --- -Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - tCard *card = Node->ImplPtr; - Uint16 read_ofs, pkt_length; - int new_read_ofs; - - ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); - -retry: - if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 ) - { - LEAVE_RET('i', 0); - } - - Mutex_Acquire( &card->ReadMutex ); - - read_ofs = inw( card->IOBase + CAPR ); - LOG("raw read_ofs = %i", read_ofs); - read_ofs = (read_ofs + 0x10) & 0xFFFF; - LOG("read_ofs = %i", read_ofs); - - pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2]; - - // Calculate new read offset - new_read_ofs = read_ofs + pkt_length + 4; - new_read_ofs = (new_read_ofs + 3) & ~3; // Align - if(new_read_ofs > card->ReceiveBufferLength) { - LOG("wrapping read_ofs"); - new_read_ofs -= card->ReceiveBufferLength; - } - new_read_ofs -= 0x10; // I dunno - LOG("new_read_ofs = %i", new_read_ofs); - - // Check for errors - if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) { - // Update CAPR - outw(card->IOBase + CAPR, new_read_ofs); - Mutex_Release( &card->ReadMutex ); - goto retry; // I feel evil - } - - // Get packet - if( Length > pkt_length ) Length = pkt_length; - memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length); - - // Update CAPR - outw(card->IOBase + CAPR, new_read_ofs); - - Mutex_Release( &card->ReadMutex ); - - LEAVE('i', Length); - - return Length; -} - -Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - int td; - Uint32 status; - tCard *card = Node->ImplPtr; - - if( Length > 1500 ) return 0; // MTU exceeded - - ENTER("pNode XLength pBuffer", Node, Length, Buffer); - - // TODO: Implement a semaphore for avaliable transmit buffers - - // Find an avaliable descriptor - Mutex_Acquire(&card->CurTXProtector); - td = card->CurTXDescriptor; - card->CurTXDescriptor ++; - card->CurTXDescriptor %= 4; - Mutex_Release(&card->CurTXProtector); - // - Lock it - Mutex_Acquire( &card->TransmitInUse[td] ); - - LOG("td = %i", td); - - // Transmit using descriptor `td` - LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]); - outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]); - LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]); - // Copy to buffer - memcpy(card->TransmitBuffers[td], Buffer, Length); - // Start - status = 0; - status |= Length & 0x1FFF; // 0-12: Length - status |= 0 << 13; // 13: OWN bit - status |= (0 & 0x3F) << 16; // 16-21: Early TX threshold (zero atm, TODO: check) - LOG("status = 0x%08x", status); - outd(card->IOBase + TSD0 + td*4, status); - - LEAVE('i', (int)Length); - - return Length; -} - -const char *csaPCnet3_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL}; -int PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Data) -{ - tCard *card = Node->ImplPtr; - ENTER("pNode iID pData", Node, ID, Data); - switch(ID) - { - BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_NodeIOCtls); - case NET_IOCTL_GETMAC: - if( !CheckMem(Data, 6) ) { - LEAVE('i', -1); - return -1; - } - memcpy( Data, card->MacAddr, 6 ); - LEAVE('i', 1); - return 1; - } - LEAVE('i', 0); - return 0; -} - -void PCnet3_IRQHandler(int Num) -{ - int i, j; - tCard *card; - Uint16 status; - - LOG("Num = %i", Num); - - for( i = 0; i < giPCnet3_CardCount; i ++ ) - { - card = &gaPCnet3_Cards[i]; - if( Num != card->IRQ ) break; - - status = inw(card->IOBase + ISR); - LOG("status = 0x%02x", status); - - // Transmit OK, a transmit descriptor is now free - if( status & FLAG_ISR_TOK ) - { - for( j = 0; j < 4; j ++ ) - { - if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK - Mutex_Release( &card->TransmitInUse[j] ); - // TODO: Update semaphore once implemented - } - } - outw(card->IOBase + ISR, FLAG_ISR_TOK); - } - - // Recieve OK, inform read - if( status & FLAG_ISR_ROK ) - { - int read_ofs, end_ofs; - int packet_count = 0; - int len; - - // Scan recieve buffer for packets - end_ofs = inw(card->IOBase + CBA); - read_ofs = card->SeenOfs; - LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs); - if( read_ofs > end_ofs ) - { - while( read_ofs < card->ReceiveBufferLength ) - { - packet_count ++; - len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2]; - LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x", - packet_count, read_ofs, - *(Uint16*)&card->ReceiveBuffer[read_ofs], - len - ); - if(len > 2000) { - Log_Warning("PCnet3", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len); - } - read_ofs += len + 4; - read_ofs = (read_ofs + 3) & ~3; // Align - } - read_ofs -= card->ReceiveBufferLength; - LOG("wrapped read_ofs"); - } - while( read_ofs < end_ofs ) - { - packet_count ++; - LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x", - packet_count, read_ofs, - *(Uint16*)&card->ReceiveBuffer[read_ofs], - *(Uint16*)&card->ReceiveBuffer[read_ofs+2] - ); - read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4; - read_ofs = (read_ofs + 3) & ~3; // Align - } - if( read_ofs != end_ofs ) { - Log_Warning("PCnet3", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs); - read_ofs = end_ofs; - } - card->SeenOfs = read_ofs; - - LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs); - - if( packet_count ) - { - if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) { - // Oops? - } - VFS_MarkAvaliable( &card->Node, 1 ); - } - - outw(card->IOBase + ISR, FLAG_ISR_ROK); - } - } -} diff --git a/KernelLand/Modules/Network/PCnetFAST3/Makefile b/KernelLand/Modules/Network/PCnetFAST3/Makefile new file mode 100644 index 00000000..46d7f2af --- /dev/null +++ b/KernelLand/Modules/Network/PCnetFAST3/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = pcnet-fast3.o +NAME = PCnetFAST3 + +-include ../Makefile.tpl diff --git a/KernelLand/Modules/Network/PCnetFAST3/hw.h b/KernelLand/Modules/Network/PCnetFAST3/hw.h new file mode 100644 index 00000000..b65ccb02 --- /dev/null +++ b/KernelLand/Modules/Network/PCnetFAST3/hw.h @@ -0,0 +1,98 @@ + +#ifndef _PCNETFAST3__HW_H_ +#define _PCNETFAST3__HW_H_ + +typedef struct sInitBlock32 tInitBlock32; +typedef struct sTxDesc_3 tTxDesc_3; +typedef struct sRxDesc_3 tRxDesc_3; + +struct sInitBlock32 +{ + Uint32 Mode; // [0:15]: MODE, [20:23] RLen, [28:31] TLen + Uint32 PhysAddr0; // MAC Address + Uint32 PhysAddr1; // [0:15] MAC Addres + Uint32 LAdrF0; // Logical Address Filter (CRC on multicast MAC, top 6 bits index bitmap) + Uint32 LAdrF1; + Uint32 RDRA; // Rx Descriptor Ring Address + Uint32 TDRA; // Tx Descriptor Ring Address +}; + +// SWSTYLE=3: 32-bit allowing burst mode +#define RXDESC_FLG_OWN (1<<31) +#define RXDESC_FLG_ENP (1<<24) +#define RXDESC_FLG_STP (1<<25) +struct sRxDesc_3 +{ + Uint32 Count; // [0:11] Message Byte Count + Uint32 Flags; // [0:11] BCNT, [23] BPE, ENP, STP, BUFF, CRC, OFLO, FRAM, ERR, OWN + Uint32 Buffer; + Uint32 _avail; // +}; + +#define TXDESC_FLG1_OWN (1 << 31) +#define TXDESC_FLG1_ADDFCS (1<<29) +#define TXDESC_FLG1_STP (1 << 25) +#define TXDESC_FLG1_ENP (1 << 24) +struct sTxDesc_3 +{ + Uint32 Flags0; // Status mostly + Uint32 Flags1; // [0:11] BCNT + Uint32 Buffer; + Uint32 _avail; +}; + +enum eRegs +{ + REG_APROM0 = 0x00, + REG_APROM4 = 0x04, + REG_APROM8 = 0x08, + REG_APROMC = 0x0C, + REG_RDP = 0x10, // 16 bit + REG_RAP = 0x14, // 8-bit + REG_RESET = 0x18, // 16-bit + REG_BDP = 0x1C, // 16-bit +}; + +#define CSR_STATUS_INIT (1<< 0) +#define CSR_STATUS_STRT (1<< 1) +#define CSR_STATUS_IENA (1<< 6) +#define CSR_STATUS_INTR (1<< 7) +#define CSR_STATUS_IDON (1<< 8) +#define CSR_STATUS_TINT (1<< 9) +#define CSR_STATUS_RINT (1<<10) + +enum eCSR_Regs +{ + CSR_STATUS, // CSR0 - Am79C973/Am79C975 Controller Status + CSR_IBA0, // CSR1 - Initialization Block Address[15:0] + CSR_IBA1, // CSR2 - Initialization Block Address[31:16] + CSR_INTMASK, // CSR3 - Interrupt Masks and Deferral Control + + CSR_LAF0 = 8, // CSR8 - Logical Address Filter[15:0] + CSR_LAF1 = 9, // CSR9 - Logical Address Filter[31:16] + CSR_LAF2 = 10, // CSR10 - Logical Address Filter[47:32] + CSR_LAF3 = 11, // CSR11 - Logical Address Filter[63:48] + CSR_MAC0 = 12, // CSR12 - Physical Address[15:0] + CSR_MAC1 = 13, // CSR13 - Physical Address[31:16] + CSR_MAC2 = 14, // CSR14 - Physical Address[47:32] + CSR_MODE = 15, // CSR15 - Mode + + CSR_RXBASE0 = 24, // CSR24 - Base Address of Receive Ring Lower + CSR_RXBASE1 = 25, // CSR25 - Base Address of Receive Ring Upper + CSR_TXBASE0 = 30, // CSR26 - Base Address of Transmit Ring Lower + CSR_TXBASE1 = 31, // CSR27 - Base Address of Transmit Ring Upper + + CSR_RXLENGTH = 76, // CSR76 - Receive Ring Length + CSR_TXLENGTH = 78, // CSR78 - Transmit Ring Length +}; + +enum eBCR_Regs +{ + BCR_SWSTYLE = 20, + BCR_PHYCS = 32, // BCR32 - Internal PHY Control and Status + BCR_PHYADDR, // BCR33 - Internal PHY Address + BCR_PHYMGMT, // BCR34 - Internal PHY Management Data +}; + +#endif + diff --git a/KernelLand/Modules/Network/PCnetFAST3/pcnet-fast3.c b/KernelLand/Modules/Network/PCnetFAST3/pcnet-fast3.c new file mode 100644 index 00000000..06c783a2 --- /dev/null +++ b/KernelLand/Modules/Network/PCnetFAST3/pcnet-fast3.c @@ -0,0 +1,523 @@ +/* + * Acess2 PCnet-FAST III Driver + * - By John Hodge (thePowersGang) + */ +#define DEBUG 1 +#define VERSION ((1<<8)|0) +#include +#include +#include +#include +#include +#include "hw.h" + +#define assert ASSERT // because CBF updating code + +// === CONSTANTS === +#define VENDOR_ID 0x1022 +#define DEVICE_ID 0x2000 +#define TLEN_LOG2 6 // 64 +#define RLEN_LOG2 7 +#define TLEN (1 << TLEN_LOG2) +#define RLEN (1 << RLEN_LOG2) +#define RXBUFLEN 128 // 128*128 = 16K total RX buffer +#define RXBUF_PER_PAGE (PAGE_SIZE/RXBUFLEN) +#define NUM_RXBUF_PAGES ((RLEN*RXBUFLEN)/PAGE_SIZE) + +// === TYPES === +typedef struct sCard +{ + Uint16 IOBase; + Uint8 IRQ; + + tPAddr TxQueuePhys; + tTxDesc_3 *TxQueue; + void *TxQueueBuffers[TLEN]; // Pointer to the tIPStackBuffer (STP only) + + tMutex lTxPos; + tSemaphore TxDescSem; + int FirstUsedTxD; + int FirstFreeTx; + + tSemaphore ReadSemaphore; + tMutex lRxPos; + int RxPos; + tPAddr RxQueuePhys; + tRxDesc_3 *RxQueue; + void *RxBuffers[NUM_RXBUF_PAGES]; // Pages + + Uint8 MacAddr[6]; + void *IPStackHandle; +} tCard; + +// === PROTOTYPES === + int PCnet3_Install(char **Options); + int PCnet3_Cleanup(void); + +tIPStackBuffer *PCnet3_WaitForPacket(void *Ptr); + int PCnet3_SendPacket(void *Ptr, tIPStackBuffer *Buffer); + + int PCnet3_int_InitCard(tCard *Card); +void PCnet3_IRQHandler(int Num, void *Ptr); +void PCnet3_ReleaseRxD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data); + +static Uint16 _ReadCSR(tCard *Card, Uint8 Reg); +static void _WriteCSR(tCard *Card, Uint8 Reg, Uint16 Value); +static Uint16 _ReadBCR(tCard *Card, Uint8 Reg); +static void _WriteBCR(tCard *Card, Uint8 Reg, Uint16 Value); + +// === GLOBALS === +MODULE_DEFINE(0, VERSION, Network_PCnetFAST3, PCnet3_Install, PCnet3_Cleanup, "IPStack", NULL); +tIPStack_AdapterType gPCnet3_AdapterType = { + .Name = "PCnet-FAST III", + .Type = 0, // TODO: Differentiate differnet wire protos and speeds + .Flags = 0, // TODO: IP checksum offloading, MAC checksum offloading etc + .SendPacket = PCnet3_SendPacket, + .WaitForPacket = PCnet3_WaitForPacket +}; + int giPCnet3_CardCount; +tCard *gaPCnet3_Cards; +// - Init +tInitBlock32 gPCnet3_StaticInitBlock; +tInitBlock32 *gpPCnet3_InitBlock; + +// === CODE === +/** + * \brief Installs the PCnet3 Driver + */ +int PCnet3_Install(char **Options) +{ + int id = -1; + int i = 0; + Uint16 base; + tCard *card; + + giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID); + Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount); + + if( giPCnet3_CardCount == 0 ) return MODULE_ERR_NOTNEEDED; + + gpPCnet3_InitBlock = &gPCnet3_StaticInitBlock; + // TODO: Edge case bug here with the block on the end of a page + if( MM_GetPhysAddr(gpPCnet3_InitBlock) + sizeof(tInitBlock32) != MM_GetPhysAddr(gpPCnet3_InitBlock+1) + #if PHYS_BITS > 32 + || MM_GetPhysAddr(gpPCnet3_InitBlock) > (1ULL<<32) + #endif + ) + { + // allocate + Log_Error("PCnet3", "TODO: Support 64-bit init / spanning init"); + return MODULE_ERR_MISC; + } + + gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) ); + + while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 ) + { + // Set up card addresses + // - BAR0: IO base address + // - BAR1: MMIO base address + card = &gaPCnet3_Cards[i]; + base = PCI_GetBAR( id, 0 ); + if( !(base & 1) ) { + Log_Warning("PCnet3", "Driver does not support MMIO, skipping card"); + card->IOBase = 0; + card->IRQ = 0; + continue ; + } + base &= ~1; + card->IOBase = base; + card->IRQ = PCI_GetIRQ( id ); + + // Switch the card into DWord mode + // - TODO: Should the value of RAP matter here? + outd(card->IOBase + REG_RDP, 0); + + // Get MAC address + #if 0 + Uint16 macword; + //macword = _ReadCSR(card, CSR_MAC0); + card->MacAddr[0] = macword & 0xFF; + card->MacAddr[1] = macword >> 8; + //macword = _ReadCSR(card, CSR_MAC1); + card->MacAddr[2] = macword & 0xFF; + card->MacAddr[3] = macword >> 8; + //macword = _ReadCSR(card, CSR_MAC2); + card->MacAddr[4] = macword & 0xFF; + card->MacAddr[5] = macword >> 8; + #else + Uint32 macword; + macword = ind(card->IOBase + REG_APROM0); + card->MacAddr[0] = macword & 0xFF; + card->MacAddr[1] = macword >> 8; + card->MacAddr[2] = macword >> 16; + card->MacAddr[3] = macword >> 24; + macword = ind(card->IOBase + REG_APROM4); + card->MacAddr[4] = macword & 0xFF; + card->MacAddr[5] = macword >> 8; + #endif + + // Install IRQ Handler + IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler, card); + + // Soft reset (read from RESET) + PCnet3_int_InitCard(card); + + + Semaphore_Init(&card->ReadSemaphore, 0, 0, "PCnet3", "CardRead"); + + // Register + card->IPStackHandle = IPStack_Adapter_Add(&gPCnet3_AdapterType, card, card->MacAddr); + + i ++; + } + + if( gpPCnet3_InitBlock != &gPCnet3_StaticInitBlock ) { + MM_UnmapHWPages( (tVAddr)gpPCnet3_InitBlock, 1 ); + } + + return MODULE_ERR_OK; +} + +int PCnet3_Cleanup(void) +{ + // TODO: Kill IPStack adapters and clean up + return -1; +} + +// --- Root Functions --- +tIPStackBuffer *PCnet3_WaitForPacket(void *Ptr) +{ + tCard *card = Ptr; + + ENTER("pPtr", Ptr); + + if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 ) + { + LEAVE_RET('n', NULL); + } + + // Get descriptor range for packet + // TODO: Replace asserts with something a little more permissive + Mutex_Acquire( &card->lRxPos ); + int first_td = card->RxPos; + int nextp_td = first_td; + assert( card->RxQueue[first_td].Flags & RXDESC_FLG_STP ); + while( !(card->RxQueue[nextp_td].Flags & RXDESC_FLG_ENP) ) + { + tRxDesc_3 *rd = &card->RxQueue[nextp_td]; + assert( !(rd->Flags & RXDESC_FLG_OWN) ); + // TODO: Check error bits properly + if( rd->Flags & 0x7C000000 ) { + Log_Notice("PCnet3", "Error bits set: 0x%x", (rd->Flags>>24) & 0x7C); + } + nextp_td = (nextp_td+1) % RLEN; + assert(nextp_td != first_td); + } + nextp_td = (nextp_td+1) % RLEN; + card->RxPos = nextp_td; + Mutex_Release( &card->lRxPos ); + + int nDesc = (nextp_td - first_td + RLEN) % RLEN; + + // Create buffer structure + // TODO: Could be more efficient by checking for buffers in the same page / fully contig allocations + // - Meh + tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(nDesc); + for( int idx = first_td; idx != nextp_td; idx = (idx+1) % RLEN ) + { + tRxDesc_3 *rd = &card->RxQueue[idx]; + void *ptr = card->RxBuffers[idx/RXBUF_PER_PAGE] + (idx%RXBUF_PER_PAGE)*RXBUFLEN; + IPStack_Buffer_AppendSubBuffer(ret, (rd->Count & 0xFFF), 0, ptr, PCnet3_ReleaseRxD, rd); + } + + LEAVE('p', ret); + return ret; +} + +int PCnet3_SendPacket(void *Ptr, tIPStackBuffer *Buffer) +{ + tCard *card = Ptr; + + if( IPStack_Buffer_GetLength(Buffer) > 1500 ) { + // MTU exceeded + return EINVAL; + } + + ENTER("pPtr pBuffer", Ptr, Buffer); + // Need a sequence of `n` transmit descriptors + // - Can assume that descriptors are consumed FIFO from the current descriptor point + int idx = 0; + int nDesc = 0; + const void *sbuf_ptr; + size_t sbuf_len; + while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &sbuf_len, &sbuf_ptr)) != -1 ) + { + nDesc ++; + #if PHYS_BITS > 32 + if( MM_GetPhysAddr(sbuf_ptr) > (1ULL<<32) ) + ; // will be bounce-buffered + else + #endif + if( MM_GetPhysAddr(sbuf_ptr)+sbuf_len != MM_GetPhysAddr(sbuf_ptr+sbuf_len) ) + { + // Split + nDesc ++; + } + } + + // - Obtain enough descriptors + int rv = Semaphore_Wait(&card->TxDescSem, nDesc); + if( rv != nDesc ) { + Log_Notice("PCnet3", "Semaphore wait interrupted, restoring %i descriptors"); + Semaphore_Signal(&card->TxDescSem, rv); + LEAVE_RET('i', EINTR); + } + Mutex_Acquire(&card->lTxPos); + int first_desc = card->FirstFreeTx; + card->FirstFreeTx = (card->FirstFreeTx + nDesc) % TLEN; + Mutex_Release(&card->lTxPos); + + // - Set up descriptors + int td_idx = first_desc; + while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &sbuf_len, &sbuf_ptr)) != -1 ) + { + tTxDesc_3 *td = &card->TxQueue[td_idx]; + assert( !(td->Flags1 & TXDESC_FLG1_OWN) ); + td_idx = (td_idx + 1) % TLEN; + + tPAddr start_phys = MM_GetPhysAddr(sbuf_ptr); + size_t page1_maxsize = PAGE_SIZE - (start_phys % PAGE_SIZE); + tPAddr end_phys = MM_GetPhysAddr(sbuf_ptr + sbuf_len-1); + + #if PHYS_BITS > 32 + if( start_phys > (1ULL<<32) || end_phys > (1ULL<<32) ) + { + // TODO: Have a global set of bounce buffers + tPAddr bounce_phys; + void *bounce_virt = MM_AllocDMA(1, 32, &bounce_phys); + memcpy(bounce_virt, sbuf_ptr, sbuf_len); + // Copy to bounce buffer + td->Flags0 = 0; + td->Flags1 = 0xF000 | sbuf_len; + td->Buffer = bounce_phys; + td->_avail = 1; + LOG("%i: Bounce buffer %P+%i (orig %P,%P) - %p", + idx, bounce_phys, sbuf_len, start_phys, end_phys, td); + } + else + #endif + if( start_phys+sbuf_len-1 != end_phys ) + { + // Split buffer into two descriptors + tTxDesc_3 *td2 = &card->TxQueue[td_idx]; + assert( !(td2->Flags1 & TXDESC_FLG1_OWN) ); + td_idx = (td_idx + 1) % TLEN; + + td->Flags0 = 0; + td->Flags1 = 0xF000 | page1_maxsize; + td->Buffer = start_phys; + td->_avail = 0; + + td2->Flags0 = 0; + td2->Flags1 = 0xF000 | (sbuf_len - page1_maxsize); + td2->Buffer = end_phys - (sbuf_len-page1_maxsize-1); + td2->_avail = 0; + td2->Flags1 |= TXDESC_FLG1_OWN; + + LOG("%i: Split (%P,%P)+%i - %p,%p", + idx, td->Buffer, td2->Buffer, sbuf_len, td, td2); + } + else + { + td->Flags0 = 0; + td->Flags1 = 0xF000 | sbuf_len; + td->Buffer = start_phys; + td->_avail = 0; + LOG("%i: Straight %P+%i - %p", + idx, td->Buffer, sbuf_len, td); + } + // On every descriptor except the first, set OWN + // - OWN set later once all are filled + if( (td_idx+TLEN-1)%TLEN != first_desc ) + td->Flags1 |= TXDESC_FLG1_OWN; + } + + // - Lock buffer before allowing the card to continue + IPStack_Buffer_LockBuffer(Buffer); + + // - Set STP/ENP + card->TxQueue[first_desc].Flags1 |= TXDESC_FLG1_STP; + card->TxQueue[(td_idx+TLEN-1)%TLEN].Flags1 |= TXDESC_FLG1_ENP|TXDESC_FLG1_ADDFCS; + // - Set OWN on the first descriptor + card->TxQueue[first_desc].Flags1 |= TXDESC_FLG1_OWN; + card->TxQueueBuffers[first_desc] = Buffer; + + LOG("CSR0=0x%x", _ReadCSR(card, 0)); + LOG("Transmit started, waiting for completion"); + + // Block here until packet is sent + // TODO: Should be able to return, but just in case + IPStack_Buffer_LockBuffer(Buffer); + IPStack_Buffer_UnlockBuffer(Buffer); + + LEAVE('i', 0); + return 0; +} + +int PCnet3_int_InitCard(tCard *Card) +{ + // Allocate ring buffers + Card->TxQueue = (void*)MM_AllocDMA(1, 32, &Card->TxQueuePhys); + if( !Card->TxQueue ) { + return MODULE_ERR_MALLOC; + } + memset(Card->TxQueue, 0, TLEN*sizeof(*Card->TxQueue)); + #if TLEN + RLEN <= PAGE_SIZE / (4*4) + Card->RxQueue = (void*)MM_AllocDMA(1, 32, &Card->RxQueuePhys); + if( !Card->RxQueue ) { + return MODULE_ERR_MALLOC; + } + #else + Card->RxQueue = Card->TxQueue + TLEN; + Card->RxQueuePhys = Card->RxQueuePhys + TLEN*sizeof(*Card->TxQueue); + #endif + + // Allocate Rx buffers + for( int i = 0; i < NUM_RXBUF_PAGES; i ++ ) + { + tPAddr physaddr; + Card->RxBuffers[i] = (void*)MM_AllocDMA(1, 32, &physaddr); + if( !Card->RxBuffers[i] ) { + return MODULE_ERR_MALLOC; + } + for( int j = 0; j < RXBUF_PER_PAGE; j ++ ) + { + Card->RxQueue[i*RXBUF_PER_PAGE+j].Buffer = physaddr; + physaddr += RXBUFLEN; + } + } + + // Initialise semaphores + Semaphore_Init(&Card->TxDescSem, TLEN, TLEN, "PCnet3", "Tx Descriptors"); + Semaphore_Init(&Card->ReadSemaphore, 0, RLEN, "PCnet3", "Rx Descriptors"); + + // Fill Init Block for this card + gpPCnet3_InitBlock->Mode = (TLEN_LOG2 << 28) | (RLEN_LOG2 << 20); + gpPCnet3_InitBlock->PhysAddr1 = 0; + memcpy(&gpPCnet3_InitBlock->PhysAddr0, Card->MacAddr, 6); + gpPCnet3_InitBlock->LAdrF0 = -1; // TODO: Allow these to be set by the IPStack + gpPCnet3_InitBlock->LAdrF1 = -1; + gpPCnet3_InitBlock->RDRA = Card->RxQueuePhys; + gpPCnet3_InitBlock->TDRA = Card->TxQueuePhys; + + // Reset card + inw(Card->IOBase + REG_RESET); + _WriteBCR(Card, BCR_SWSTYLE, (1<<8)|3); // Set SSIZE32 + LOG("BCR_SWSTYLE reads as 0x%x", _ReadBCR(Card, BCR_SWSTYLE)); + LOG("CSR4 reads as 0x%x", _ReadCSR(Card, 4)); + + // Initialise + tPAddr paddr = MM_GetPhysAddr(gpPCnet3_InitBlock); + _WriteCSR(Card, CSR_IBA0, paddr & 0xFFFF); + _WriteCSR(Card, CSR_IBA1, paddr >> 16); + _WriteCSR(Card, CSR_STATUS, CSR_STATUS_INIT|CSR_STATUS_IENA|CSR_STATUS_STRT); + + return 0; +} + +void PCnet3_IRQHandler(int Num, void *Ptr) +{ + tCard *card = Ptr; + Uint16 status = _ReadCSR(card, CSR_STATUS); + + LOG("status = 0x%02x", status); + status &= ~CSR_STATUS_INTR; // Read-only bit + + // Rx Interrupt + // META - Check LAPPEN bit in CSR3 + if( status & CSR_STATUS_RINT ) + { + // TODO: Avoid issues when two packets arrive in one interrupt time + Semaphore_Signal(&card->ReadSemaphore, 1); + } + + // Tx Interrupt + if( status & CSR_STATUS_TINT ) + { + int idx; + for( idx = card->FirstUsedTxD; idx != card->FirstFreeTx; idx = (idx+1)%TLEN ) + { + tTxDesc_3 *td = &card->TxQueue[idx]; + // Stop on the first chip-owned TxD + LOG("idx=%i, Flags1=0x%08x", idx, td->Flags1); + if( td->Flags1 & TXDESC_FLG1_OWN ) + break; + if( td->Flags1 & (1<<30) ) + { + LOG(" Flags0=0x%08x %s%s%s%s%s%s%i", + td->Flags0, + (td->Flags0 & (1<<31)) ? "BUFF " : "", + (td->Flags0 & (1<<30)) ? "UFLO " : "", + (td->Flags0 & (1<<29)) ? "EXDEF " : "", + (td->Flags0 & (1<<28)) ? "LCOL " : "", + (td->Flags0 & (1<<27)) ? "LCAR " : "", + (td->Flags0 & (1<<26)) ? "RTRY " : "", + td->Flags0 & 15 + ); + } + if( td->Flags1 & TXDESC_FLG1_STP ) + IPStack_Buffer_UnlockBuffer( card->TxQueueBuffers[idx] ); + Semaphore_Signal(&card->TxDescSem, 1); + } + card->FirstUsedTxD = idx; + } + + if( status & CSR_STATUS_IDON ) + { + Log_Debug("PCnet3", "Card %p initialisation done", card); + } + + // ERR set? + if( status & 0xBC00 ) + { + Log_Notice("PCnet3", "Error on %p: %s%s%s%s", + card, + (status & (1<<15)) ? "ERR " : "", + (status & (1<<13)) ? "CERR " : "", + (status & (1<<12)) ? "MISS " : "", + (status & (1<<11)) ? "MERR " : "" + ); + } + + _WriteCSR(card, CSR_STATUS, status); +} + +void PCnet3_ReleaseRxD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data) +{ + tRxDesc_3 *rd = Arg; + rd->Flags &= 0xFFFF; + rd->Flags |= RXDESC_FLG_OWN; +} + +static Uint16 _ReadCSR(tCard *Card, Uint8 Reg) +{ + outd(Card->IOBase + REG_RAP, Reg); + return ind(Card->IOBase + REG_RDP); +} +static void _WriteCSR(tCard *Card, Uint8 Reg, Uint16 Value) +{ + outd(Card->IOBase + REG_RAP, Reg); + outd(Card->IOBase + REG_RDP, Value); +} +static Uint16 _ReadBCR(tCard *Card, Uint8 Reg) +{ + outd(Card->IOBase + REG_RAP, Reg); + return ind(Card->IOBase + REG_BDP); +} +void _WriteBCR(tCard *Card, Uint8 Reg, Uint16 Value) +{ + outd(Card->IOBase + REG_RAP, Reg); + outd(Card->IOBase + REG_BDP, Value); +} + -- 2.20.1