Modules/PCnetFAST3 - Quieten
[tpg/acess2.git] / KernelLand / Modules / Network / PRO100 / main.c
index 13ef216..d75571d 100644 (file)
@@ -5,9 +5,9 @@
  * main.c
  * - Driver core
  *
- * Built with reference to the linux e100 driver (drivers/net/ethernet/intel/e100.c)
- * 82559-fast-ethernet-multifunciton-pci-datasheet.pdf
+ * 8255x (Intel 8255x 10/100 Mbps Ethernet Controller Family)
  */
+#define DEBUG  1
 #include <acess.h>
 #include <IPStack/include/adapters_api.h>
 #include <modules.h>
 
 // === 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 +31,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 ===
@@ -43,7 +46,7 @@ MODULE_DEFINE(0, 0x100, PRO100, PRO100_Install, PRO100_Cleanup, "IPStack", NULL)
 tIPStack_AdapterType   gPRO100_AdapterType = {
        .Name = "PRO/100",
        .Type = ADAPTERTYPE_ETHERNET_100M,
-       .Flags = 0,     
+       .Flags = ADAPTERFLAG_OFFLOAD_MAC,       
        .SendPacket = PRO100_SendPacket,
        .WaitForPacket = PRO100_WaitForPacket
 };
@@ -56,10 +59,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 +77,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 +93,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 +104,78 @@ 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]);
+       }
+       
+       _Write32(Card, REG_GenPtr, 0);
+       _FlushWait(Card, 4);
+       _Write16(Card, REG_Command, CU_CMD_BASE);
+       _FlushWait(Card, 4);
+       // Ensure CU is in suspend before we attempt sending
+       Card->LastTXIndex = 1;
+       Card->CurTXIndex = 1;
+       _Write32(Card, REG_GenPtr, txbase);
+       _FlushWait(Card, 4);
+       _Write16(Card, REG_Command, CU_CMD_START);
+       _FlushWait(Card, 4);
 
        // 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->Count = 0;  // clears bit 14
+                       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]);
+       }
+       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);
-       
        _Write32(Card, REG_GenPtr, 0);
-       _Write32(Card, REG_Command, RX_CMD_START);
+       _FlushWait(Card, 4);
+       _Write16(Card, REG_Command, RX_CMD_ADDR_LOAD);
+       _FlushWait(Card, 4);
        
+       _Write32(Card, REG_GenPtr, rx_desc_phys);
+       _FlushWait(Card, 4);
+       _Write16(Card, REG_Command, RX_CMD_START);
+       _FlushWait(Card, 4);
+
        return 0;
 }
 
@@ -109,32 +184,208 @@ 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;
+       buf->Count = 0;
+       prev->CU.Command &= ~CMD_Suspend;
+       
+       // Resume
+       _Write16(Card, REG_Command, RX_CMD_RESUME);
+       _FlushWait(Card, 4);
+}
+
+
 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];
+       Card->CurRXIndex = (Card->CurRXIndex+1) % NUM_RX;
+       
+       // Return packet (freed in PRO100_ReleaseRXBuf);
+       tIPStackBuffer  *ret = IPStack_Buffer_CreateBuffer(1);
+       size_t  bytes = buf->Count & 0x3FFF;
+       // - actual data is just after the descriptor
+       IPStack_Buffer_AppendSubBuffer(ret, bytes, 0, buf+1, PRO100_ReleaseRXBuf, Card);
+
+       LOG("RX'd 0x%x bytes", bytes);
+
+       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 | (1 << 15);
+       txc->Desc.TXThreshold = 3;      // Start transmitting after 3*8 bytes
+       txc->Desc.TBDCount = 0;
+       txc->Desc.CU.Command = CMD_Suspend|CMD_Tx;
+       txc->Desc.CU.Status = 0;
+       IPStack_Buffer_LockBuffer(Buffer);
+       // - Mark previous as not suspended
+       Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend;
+
+       LOG("Starting send on txc_idx=%i", txc_idx);
+       LOG("- REG_Status = %x", _Read8(Card, REG_Status));
+
+       // 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);
+       _FlushWait(Card, 4);
+
+       IPStack_Buffer_LockBuffer(Buffer);
+       IPStack_Buffer_UnlockBuffer(Buffer);
+
+       LOG("- CU Status = 0x%x", txc->Desc.CU.Status);
+
+       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_FCP ) {
+               LOG("FCP - Flow Control Pause");
+       }
+       if( status & ISR_ER ) {
+               LOG("ER - Early Receive");
+       }
+       if( status & ISR_SWI ) {
+               LOG("SWI - Software interrupt");
+       }
+       if( status & ISR_MDI ) {
+               LOG("MDI - Management Data Interface");
+       }
+
+       if( status & ISR_RNR ) {
+               LOG("RNR - Recieve not ready");
+       }
+       if( status & ISR_CNA )
+       {
+               LOG("CNA - Command unit Not Active");
+               // 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);
+       }
+       if( status & ISR_FR ) {
+               LOG("FR - Frame recieved");
+               Semaphore_Signal(&Card->RXSemaphore, 1);
+               LOG("- RX signaled");
+       }
+       if( status & ISR_CX ) {
+               LOG("CX - Command executed");
+       }
 }
 
-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 +397,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 +410,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)
 {

UCC git Repository :: git.ucc.asn.au