From: John Hodge Date: Sat, 10 Aug 2013 12:09:43 +0000 (+0800) Subject: Modules/PRO100 - Successfully gets a DHCP lease X-Git-Tag: rel0.15~282 X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=fc261f5d8a0c8ede562802ea4aec857a257c6cb5;p=tpg%2Facess2.git Modules/PRO100 - Successfully gets a DHCP lease --- diff --git a/KernelLand/Modules/Network/PRO100/main.c b/KernelLand/Modules/Network/PRO100/main.c index 13ef2167..db768445 100644 --- a/KernelLand/Modules/Network/PRO100/main.c +++ b/KernelLand/Modules/Network/PRO100/main.c @@ -8,6 +8,7 @@ * Built with reference to the linux e100 driver (drivers/net/ethernet/intel/e100.c) * 82559-fast-ethernet-multifunciton-pci-datasheet.pdf */ +#define DEBUG 1 #include #include #include @@ -17,10 +18,11 @@ // === CONSTANTS === #define NUM_STATIC_CARDS 2 -const Uint16 caSupportedCards[][2] = { - {0x8086, 0x103D}, +static const Uint16 caSupportedCards[][2] = { + {0x8086, 0x103D}, // prelude's card + {0x8086, 0x1209}, // qemu's i82559 emulation }; -const int ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]); +static const int ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]); // === PROTOTYPES === int PRO100_Install(char **Arguments); @@ -30,12 +32,14 @@ tIPStackBuffer *PRO100_WaitForPacket(void *Ptr); int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer); void PRO100_IRQHandler(int Num, void *Ptr); -Uint16 PRO100_int_ReadEEPROM(tCard *Card, size_t Ofs); +Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *AddrLen, size_t Ofs); +static void _Write8(tCard *Card, int Ofs, Uint8 Val); static void _Write16(tCard *Card, int Ofs, Uint16 Val); static void _Write32(tCard *Card, int Ofs, Uint32 Val); +static Uint8 _Read8(tCard *Card, int Ofs); static Uint16 _Read16(tCard *Card, int Ofs); -static Uint32 _Read32(tCard *Card, int Ofs); +//static Uint32 _Read32(tCard *Card, int Ofs); static void _FlushWait(tCard *Card, int Delay); // === GLOBALS === @@ -56,10 +60,17 @@ int PRO100_Install(char **Arguments) for( int i = 0; i < ciNumSupportedCards; i ++ ) { const Uint16 *ven_dev = caSupportedCards[i]; - int pciid = -1; - while( -1 != (pciid = PCI_GetDevice(ven_dev[0], ven_dev[1], pciid)) ) + LOG("Checking %04x:%04x: %i reported", ven_dev[0], ven_dev[1], + PCI_CountDevices(ven_dev[0], ven_dev[1])); + for( int idx = 0, pciid = -1; -1 != (pciid = PCI_GetDevice(ven_dev[0], ven_dev[1], idx)); idx++ ) { - Uint32 base = PCI_GetValidBAR(pciid, 0, PCI_BARTYPE_MEM32); + Uint8 irq = PCI_GetIRQ(pciid); + Uint32 mmiobase = PCI_GetValidBAR(pciid, 0, PCI_BARTYPE_MEM32); + Uint16 iobase = PCI_GetValidBAR(pciid, 1, PCI_BARTYPE_IO); + LOG("IO Base = %x, MMIOBase = %x", iobase, mmiobase); + + PCI_SetCommand(pciid, PCI_CMD_IOENABLE|PCI_CMD_BUSMASTER, 0); + tCard *card; if( cardidx < NUM_STATIC_CARDS ) { card = &gaPRO100_StaticCards[cardidx++]; @@ -67,8 +78,10 @@ int PRO100_Install(char **Arguments) else { card = malloc(sizeof(tCard)); } - - card->MMIO = MM_MapHWPages(base, 1); + + card->IOBase = iobase; + //card->MMIO = MM_MapHWPages(mmiobase, 1); + IRQ_AddHandler(irq, PRO100_IRQHandler, card); // TODO: Error check PRO100_InitCard(card); @@ -81,6 +94,10 @@ int PRO100_Install(char **Arguments) int PRO100_InitCard(tCard *Card) { + // Initialise structures + Semaphore_Init(&Card->TXCommandSem, NUM_TX, NUM_TX, "PRO100", "Command Buffers"); + Semaphore_Init(&Card->RXSemaphore, 0, NUM_RX, "PRO100", "Receive"); + // Card reset _Write32(Card, REG_Port, PORT_SELECTIVERESET); _FlushWait(Card, 20); // - Write Flush, wait 20us @@ -88,19 +105,69 @@ int PRO100_InitCard(tCard *Card) _FlushWait(Card, 20); // - Write Flush, wait 20us // Read MAC address - Card->MAC.Words[0] = PRO100_int_ReadEEPROM(Card, 0); - Card->MAC.Words[1] = PRO100_int_ReadEEPROM(Card, 1); - Card->MAC.Words[2] = PRO100_int_ReadEEPROM(Card, 2); + Uint8 addr_len = 8; // default to 8, updated on first read + Card->MAC.Words[0] = PRO100_int_ReadEEPROM(Card, &addr_len, 0); + Card->MAC.Words[1] = PRO100_int_ReadEEPROM(Card, &addr_len, 1); + Card->MAC.Words[2] = PRO100_int_ReadEEPROM(Card, &addr_len, 2); + + // Set interrupt mask + _Write8(Card, REG_IntMask, 0); + + // Prepare Command Unit + Card->TXCommands = MM_AllocDMA(1, 32, NULL); + Uint32 txbase = MM_GetPhysAddr(Card->TXCommands); + ASSERT(Card->TXCommands); + for( int i = 0; i < NUM_TX; i ++ ) + { + tCommandUnit *cu = &Card->TXCommands[i].Desc.CU; + cu->Status = 0; + cu->Command = CMD_Nop|CMD_Suspend; + cu->Link = MM_GetPhysAddr(&Card->TXCommands[(i+1)%NUM_TX]) - txbase; + } + + _Write32(Card, REG_GenPtr, txbase); + _Write16(Card, REG_Command, CU_CMD_BASE); + // Ensure CU is in suspend before we attempt sending + Card->LastTXIndex = 1; + Card->CurTXIndex = 1; + _Write32(Card, REG_GenPtr, 0); + _Write16(Card, REG_Command, CU_CMD_START); // Create RX Descriptors + for( int i = 0; i < NUM_RX; i += 2 ) + { + char *base = MM_AllocDMA(1, 32, NULL); + ASSERT(base); + Card->RXBufs[i+0] = (void*)base; + Card->RXBufs[i+1] = (void*)(base + 0x800); + for( int j = 0; j < 2; j ++ ) + { + tRXBuffer *rx = Card->RXBufs[i+j]; + rx->CU.Status = 0; + rx->CU.Command = 0; + // Link is populated later + rx->Size = RX_BUF_SIZE; + rx->RXBufAddr = 0; // unused? + } + } + + // NOTE: All `Link` values are relative to the RX base address + Uint32 rx_desc_phys = MM_GetPhysAddr(Card->RXBufs[0]); + for( int i = 0; i < NUM_RX-1; i ++ ) + { + tRXBuffer *rx = Card->RXBufs[i]; + rx->CU.Link = MM_GetPhysAddr(Card->RXBufs[i+1]) - rx_desc_phys; + } + Card->RXBufs[NUM_RX-1]->CU.Command = CMD_Suspend; + Card->RXBufs[NUM_RX-1]->CU.Link = 0; // link = 0, loop back // Set RX Buffer base _Write32(Card, REG_GenPtr, rx_desc_phys); - _Write32(Card, REG_Command, RX_CMD_ADDR_LOAD); + _Write16(Card, REG_Command, RX_CMD_ADDR_LOAD); _Write32(Card, REG_GenPtr, 0); - _Write32(Card, REG_Command, RX_CMD_START); - + _Write16(Card, REG_Command, RX_CMD_START); + return 0; } @@ -109,32 +176,176 @@ int PRO100_Cleanup(void) return 0; } +void PRO100_ReleaseRXBuf(void *Arg, size_t HeadLen, size_t FootLen, const void *Data) +{ + tCard *Card = Arg; + tRXBuffer *buf = (tRXBuffer*)Data - 1; + + int idx; + for( idx = 0; idx < NUM_RX && Card->RXBufs[idx] != buf; idx ++ ) + ; + ASSERT(idx != NUM_RX); + + tRXBuffer *prev = Card->RXBufs[ (idx-1+NUM_RX)%NUM_RX ]; + buf->CU.Status = 0; + buf->CU.Command = 0; + prev->CU.Command &= ~CMD_Suspend; + + // Resume + _Write16(Card, REG_Command, RX_CMD_RESUME); +} + + tIPStackBuffer *PRO100_WaitForPacket(void *Ptr) { - return NULL; + tCard *Card = Ptr; + // Wait for a packet + do { + Semaphore_Wait(&Card->RXSemaphore, 1); + } while( Card->RXBufs[Card->CurRXIndex]->CU.Status == 0 ); + // Mark previous buffer as suspend (stops the RX unit running into old packets + Card->RXBufs[ (Card->CurRXIndex-1+NUM_RX)%NUM_RX ]->CU.Command |= CMD_Suspend; + tRXBuffer *buf = Card->RXBufs[Card->CurRXIndex++]; + + // Return packet (freed in PRO100_ReleaseRXBuf); + tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(1); + // - actual data is just after the descriptor + IPStack_Buffer_AppendSubBuffer(ret, buf->Count, 0, buf+1, PRO100_ReleaseRXBuf, Card); + + return ret; +} + +void PRO100_int_SetBuf(tTXCommand *TXC, int *IndexPtr, Uint32 Addr, Uint16 Len) +{ + ASSERTC(*IndexPtr, <, NUM_LOCAL_TXBUFS); + + tTXBufDesc *txb = &TXC->LocalBufs[*IndexPtr]; + txb->Addr = Addr; + txb->Len = Len; + (*IndexPtr) ++; } int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer) { - return -1; + tCard *Card = Ptr; + + Semaphore_Wait(&Card->TXCommandSem, 1); + + // Acquire a command buffer + Mutex_Acquire(&Card->lTXCommands); + int txc_idx = Card->CurTXIndex; + Card->CurTXIndex = (Card->CurTXIndex + 1) % NUM_TX; + Mutex_Release(&Card->lTXCommands); + tTXCommand *txc = &Card->TXCommands[txc_idx]; + + // Populate + int txb_idx = 0; + const void *ptr; + size_t len; + size_t total_size = 0; + int buf_idx = -1; + while( (buf_idx = IPStack_Buffer_GetBuffer(Buffer, buf_idx, &len, &ptr)) != -1 ) + { + #if PHYS_BITS > 32 + if( MM_GetPhysAddr(ptr) >> 32 ) { + // Need to bounce + TODO(); + continue ; + } + #endif + + ASSERTC(len, <, PAGE_SIZE); + + // Check if buffer split is required + if( MM_GetPhysAddr((char*)ptr + len-1) != MM_GetPhysAddr(ptr)+len-1 ) + { + // Need to split buffer + size_t space = PAGE_SIZE - ((tVAddr)ptr % PAGE_SIZE); + PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), space); + PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr((char*)ptr+space), len-space); + } + else + { + // Single buffer + PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), len); + } + + total_size += len; + } + + // Set buffer pointer + Card->TXBuffers[txc_idx] = Buffer; + // Mark as usable + txc->Desc.TBDArrayAddr = 0xFFFFFFFF; + txc->Desc.TCBBytes = total_size; + txc->Desc.TXThreshold = 0; // TODO: What does this do on RHW? + txc->Desc.TBDCount = 0; + txc->Desc.CU.Command = CMD_Suspend|CMD_Tx; + // - Mark previous as not suspended + Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend; + + IPStack_Buffer_LockBuffer(Buffer); + + // And dispatch + // - If currently running or idle, this should not matter + // NOTE: Qemu describes this behavior as 'broken' + _Write16(Card, REG_Command, CU_CMD_RESUME); + + IPStack_Buffer_LockBuffer(Buffer); + IPStack_Buffer_UnlockBuffer(Buffer); + + return 0; } void PRO100_IRQHandler(int Num, void *Ptr) { + tCard *Card = Ptr; + Uint8 status = _Read8(Card, REG_Ack); + + if( !status ) + return ; + _Write8(Card, REG_Ack, status); + LOG("status = %x", status); + if( status & ISR_FR ) { + LOG("FR"); + Semaphore_Signal(&Card->RXSemaphore, 1); + } + + // CU Idle + if( status & ISR_CNA ) + { + // Chase the next command buffer + while( Card->LastTXIndex != Card->CurTXIndex ) + { + int idx = Card->LastTXIndex++; + // Once we hit an incomplete command, stop + if( !(Card->TXCommands[idx].Desc.CU.Status & CU_Status_Complete) ) + break ; + IPStack_Buffer_UnlockBuffer( Card->TXBuffers[idx] ); + Semaphore_Signal(&Card->TXCommandSem, 1); + } + LOG("CU Idle (%i / %i)", Card->LastTXIndex, Card->CurTXIndex); + } } -Uint16 PRO100_int_ReadEEPROM(tCard *Card, size_t Ofs) +Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *addr_len, size_t Ofs) { - Uint8 addr_len = 8; - Uint32 addr_data = ((EEPROM_OP_READ << addr_len) | Ofs) << 16; + ASSERTC( *addr_len, <=, 12 ); + Uint32 addr_data = ((EEPROM_OP_READ << *addr_len) | Ofs) << 16; + + // Deslect chip (god knows what state it was left in) + _Write16( Card, REG_EEPROMCtrl, 0 ); + _FlushWait(Card, 4); // Flush + 4us + // Raise CS _Write16( Card, REG_EEPROMCtrl, EEPROM_CTRL_CS | EEPROM_CTRL_SK ); _FlushWait(Card, 4); // Flush + 4us Uint32 data = 0; - for( int i = 32; i --; ) + // 2 preamble (0,1) + 2 command (read=1,0) + n address + 16 data + for( int i = (2+2+*addr_len+16); i --; ) { Uint16 ctrl = EEPROM_CTRL_CS | ((addr_data & (1 << i)) ? EEPROM_CTRL_DI : 0); _Write16( Card, REG_EEPROMCtrl, ctrl ); @@ -146,8 +357,10 @@ Uint16 PRO100_int_ReadEEPROM(tCard *Card, size_t Ofs) // Once the address is fully recieved, the card emits a zero bit if( !(ctrl & EEPROM_CTRL_DO) && i > 16 ) { - addr_len = addr_len - (i - 16); - i = 17; + *addr_len = *addr_len - (i - 16); + LOG("addr_len = %i", *addr_len); + + i = 16; } data = (data << 1) | (ctrl & EEPROM_CTRL_DO ? 1 : 0); @@ -157,13 +370,36 @@ Uint16 PRO100_int_ReadEEPROM(tCard *Card, size_t Ofs) _Write16( Card, REG_EEPROMCtrl, 0 ); _FlushWait(Card, 4); // Flush + 4us + LOG("Read %x from EEPROM ofs %i", data&0xFFFF, Ofs); return (data & 0xFFFF); } -static void _Write16(tCard *Card, int Ofs, Uint16 Val) { outw(Card->IOBase + Ofs, Val); } -static void _Write32(tCard *Card, int Ofs, Uint32 Val) { outd(Card->IOBase + Ofs, Val); } -static Uint16 _Read16(tCard *Card, int Ofs) { return inw(Card->IOBase + Ofs); } -static Uint32 _Read32(tCard *Card, int Ofs) { return ind(Card->IOBase + Ofs); } +static void _Write8(tCard *Card, int Ofs, Uint8 Val) { + //LOG("%p +%i := %02x", Card, Ofs, Val); + outb(Card->IOBase + Ofs, Val); +} +static void _Write16(tCard *Card, int Ofs, Uint16 Val) { + //LOG("%p +%i := %04x", Card, Ofs, Val); + ASSERT( !(Ofs & 1) ); + outw(Card->IOBase + Ofs, Val); +} +static void _Write32(tCard *Card, int Ofs, Uint32 Val) { + //LOG("%p +%i := %08x", Card, Ofs, Val); + ASSERT( !(Ofs & 3) ); + outd(Card->IOBase + Ofs, Val); +} +static Uint8 _Read8(tCard *Card, int Ofs) { + Uint8 rv = inb(Card->IOBase + Ofs); + //LOG("%p +%i == %02x", Card, Ofs, rv); + return rv; +} +static Uint16 _Read16(tCard *Card, int Ofs) { + ASSERT( !(Ofs & 1) ); + Uint16 rv = inw(Card->IOBase + Ofs); + //LOG("%p +%i == %04x", Card, Ofs, rv); + return rv; +} +//static Uint32 _Read32(tCard *Card, int Ofs) { return ind(Card->IOBase + Ofs); } static void _FlushWait(tCard *Card, int Delay) { diff --git a/KernelLand/Modules/Network/PRO100/pro100.h b/KernelLand/Modules/Network/PRO100/pro100.h index 2bcc7825..d61c22b9 100644 --- a/KernelLand/Modules/Network/PRO100/pro100.h +++ b/KernelLand/Modules/Network/PRO100/pro100.h @@ -10,6 +10,13 @@ #include "pro100_hw.h" +#include +#include + +#define NUM_RX 4 +#define RX_BUF_SIZE ((PAGE_SIZE/2)-sizeof(tRXBuffer)) +#define NUM_TX (PAGE_SIZE/sizeof(tTXCommand)) + typedef struct sCard tCard; struct sCard @@ -22,7 +29,16 @@ struct sCard Uint16 Words[3]; // Used to read the MAC from EEPROM } MAC; - //tIPStackBuffer *TXBuffers[NUM_TX]; + int CurRXIndex; + tRXBuffer *RXBufs[NUM_RX]; + tSemaphore RXSemaphore; + + tSemaphore TXCommandSem; + tMutex lTXCommands; + int LastTXIndex; + int CurTXIndex; + tTXCommand *TXCommands; + tIPStackBuffer *TXBuffers[NUM_TX]; }; #endif diff --git a/KernelLand/Modules/Network/PRO100/pro100_hw.h b/KernelLand/Modules/Network/PRO100/pro100_hw.h index cc665c37..e1b00575 100644 --- a/KernelLand/Modules/Network/PRO100/pro100_hw.h +++ b/KernelLand/Modules/Network/PRO100/pro100_hw.h @@ -8,6 +8,13 @@ #ifndef _PRO100_HW_H_ #define _PRO100_HW_H_ +// Want at least 5 TX Buffer slots (for TCP) +// - However, bounce buffers are annoying, so double that +#define MIN_LOCAL_TXBUFS 5*2 +// - 16 bytes per TX header, plus 8 per buffer, want 16 byte alignment +// - need to round up to multiple of 2 +#define NUM_LOCAL_TXBUFS ((MIN_LOCAL_TXBUFS+1)&~(2-1)) + enum ePro100_Regs { REG_Status, REG_Ack, @@ -40,14 +47,14 @@ struct sCSR #define STATUS_RUS_MASK 0x003C // Receive Unit Status #define STATUS_CUS_MASK 0x00C0 // Comamnd Unit Status -#define STATUS_FCP 0x0100 // Flow Control Pause -#define STATUS_ER 0x0200 // Early Recieve -#define STATUS_SWI 0x0400 // Software Interrupt -#define STATUS_MDI 0x0800 // Management Data Interrupt -#define STATUS_RNR 0x1000 // Receive Not Ready -#define STATUS_CNA 0x2000 // Command Unit not active -#define STATUS_FR 0x4000 // Frame Recieved -#define STATUS_CX 0x8000 // Command Unit executed +#define ISR_FCP 0x01 // Flow Control Pause +#define ISR_ER 0x02 // Early Recieve +#define ISR_SWI 0x04 // Software Interrupt +#define ISR_MDI 0x08 // Management Data Interrupt +#define ISR_RNR 0x10 // Receive Not Ready +#define ISR_CNA 0x20 // Command Unit not active +#define ISR_FR 0x40 // Frame Recieved +#define ISR_CX 0x80 // Command Unit executed #define CMD_RUC 0x0007 #define CMD_CUC 0x00F0 @@ -95,25 +102,62 @@ enum eCommands { CMD_Tx, }; -typedef struct sCommandUnit +#define CMD_IOC (1 << 13) // Interrupt on completion +#define CMD_Suspend (1 << 14) // Suspend upon completion +#define CMD_EL (1 << 15) // Stop upon completion + +#define CU_Status_Complete (1 << 15) + +typedef struct sCommandUnit tCommandUnit; + +struct sCommandUnit { Uint16 Status; Uint16 Command; - Uint32 Link; + Uint32 Link; // Relative to base +} ALIGN(4); + +typedef struct sTXDescriptor tTXDescriptor; +typedef struct sTXBufDesc tTXBufDesc; +typedef struct sTXCommand tTXCommand; + +// - Core TX Descriptor +struct sTXDescriptor +{ + tCommandUnit CU; + + Uint32 TBDArrayAddr; + Uint16 TCBBytes; + Uint8 TXThreshold; + Uint8 TBDCount; }; -typedef struct sRXBuffer tRXBuffer; +// - TX Buffer descriptor (pointed to by TBDArrayAddr, or following sTXDescriptor) +struct sTXBufDesc +{ + Uint32 Addr; + Uint16 Len; + Uint16 EndOfList; +}; + +// - TX Command block (used by static allocation) +struct sTXCommand +{ + tTXDescriptor Desc; + tTXBufDesc LocalBufs[NUM_LOCAL_TXBUFS]; +}; +typedef struct sRXBuffer tRXBuffer; struct sRXBuffer { - Uint16 Status; - Uint16 Command; - Uint32 Link; // Base from RX base + // Status: + // - [1]: ??? + tCommandUnit CU; Uint32 RXBufAddr; // Unused according to qemu source Uint16 Count; Uint16 Size; -} ALIGN(4); +}; #endif