Modules/PRO100 - Successfully gets a DHCP lease
authorJohn Hodge <[email protected]>
Sat, 10 Aug 2013 12:09:43 +0000 (20:09 +0800)
committerJohn Hodge <[email protected]>
Sat, 10 Aug 2013 12:09:43 +0000 (20:09 +0800)
KernelLand/Modules/Network/PRO100/main.c
KernelLand/Modules/Network/PRO100/pro100.h
KernelLand/Modules/Network/PRO100/pro100_hw.h

index 13ef216..db76844 100644 (file)
@@ -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 <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 +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)
 {
index 2bcc782..d61c22b 100644 (file)
 
 #include "pro100_hw.h"
 
+#include <semaphore.h>
+#include <mutex.h>
+
+#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
index cc665c3..e1b0057 100644 (file)
@@ -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
 

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