2 * Acess2 PRO/100 Driver
3 * - By John Hodge (thePowersGang)
8 * 8255x (Intel 8255x 10/100 Mbps Ethernet Controller Family)
12 #include <IPStack/include/adapters_api.h>
19 #define NUM_STATIC_CARDS 2
20 static const Uint16 caSupportedCards[][2] = {
21 {0x8086, 0x103D}, // prelude's card
22 {0x8086, 0x1209}, // qemu's i82559 emulation
24 static const int ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]);
27 int PRO100_Install(char **Arguments);
28 int PRO100_InitCard(tCard *Card);
29 int PRO100_Cleanup(void);
30 tIPStackBuffer *PRO100_WaitForPacket(void *Ptr);
31 int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
32 void PRO100_IRQHandler(int Num, void *Ptr);
34 Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *AddrLen, size_t Ofs);
36 static void _Write8(tCard *Card, int Ofs, Uint8 Val);
37 static void _Write16(tCard *Card, int Ofs, Uint16 Val);
38 static void _Write32(tCard *Card, int Ofs, Uint32 Val);
39 static Uint8 _Read8(tCard *Card, int Ofs);
40 static Uint16 _Read16(tCard *Card, int Ofs);
41 //static Uint32 _Read32(tCard *Card, int Ofs);
42 static void _FlushWait(tCard *Card, int Delay);
45 MODULE_DEFINE(0, 0x100, PRO100, PRO100_Install, PRO100_Cleanup, "IPStack", NULL);
46 tIPStack_AdapterType gPRO100_AdapterType = {
48 .Type = ADAPTERTYPE_ETHERNET_100M,
49 .Flags = ADAPTERFLAG_OFFLOAD_MAC,
50 .SendPacket = PRO100_SendPacket,
51 .WaitForPacket = PRO100_WaitForPacket
53 tCard gaPRO100_StaticCards[NUM_STATIC_CARDS];
56 int PRO100_Install(char **Arguments)
59 for( int i = 0; i < ciNumSupportedCards; i ++ )
61 const Uint16 *ven_dev = caSupportedCards[i];
62 LOG("Checking %04x:%04x: %i reported", ven_dev[0], ven_dev[1],
63 PCI_CountDevices(ven_dev[0], ven_dev[1]));
64 for( int idx = 0, pciid = -1; -1 != (pciid = PCI_GetDevice(ven_dev[0], ven_dev[1], idx)); idx++ )
66 Uint8 irq = PCI_GetIRQ(pciid);
67 Uint32 mmiobase = PCI_GetValidBAR(pciid, 0, PCI_BARTYPE_MEM32);
68 Uint16 iobase = PCI_GetValidBAR(pciid, 1, PCI_BARTYPE_IO);
69 LOG("IO Base = %x, MMIOBase = %x", iobase, mmiobase);
71 PCI_SetCommand(pciid, PCI_CMD_IOENABLE|PCI_CMD_BUSMASTER, 0);
74 if( cardidx < NUM_STATIC_CARDS ) {
75 card = &gaPRO100_StaticCards[cardidx++];
78 card = malloc(sizeof(tCard));
81 card->IOBase = iobase;
82 //card->MMIO = MM_MapHWPages(mmiobase, 1);
83 IRQ_AddHandler(irq, PRO100_IRQHandler, card);
86 PRO100_InitCard(card);
88 IPStack_Adapter_Add(&gPRO100_AdapterType, card, card->MAC.Bytes);
94 int PRO100_InitCard(tCard *Card)
96 // Initialise structures
97 Semaphore_Init(&Card->TXCommandSem, NUM_TX, NUM_TX, "PRO100", "Command Buffers");
98 Semaphore_Init(&Card->RXSemaphore, 0, NUM_RX, "PRO100", "Receive");
101 _Write32(Card, REG_Port, PORT_SELECTIVERESET);
102 _FlushWait(Card, 20); // - Write Flush, wait 20us
103 _Write32(Card, REG_Port, PORT_SOFTWARERESET);
104 _FlushWait(Card, 20); // - Write Flush, wait 20us
107 Uint8 addr_len = 8; // default to 8, updated on first read
108 Card->MAC.Words[0] = PRO100_int_ReadEEPROM(Card, &addr_len, 0);
109 Card->MAC.Words[1] = PRO100_int_ReadEEPROM(Card, &addr_len, 1);
110 Card->MAC.Words[2] = PRO100_int_ReadEEPROM(Card, &addr_len, 2);
112 // Set interrupt mask
113 _Write8(Card, REG_IntMask, 0);
115 // Prepare Command Unit
116 Card->TXCommands = MM_AllocDMA(1, 32, NULL);
117 Uint32 txbase = MM_GetPhysAddr(Card->TXCommands);
118 ASSERT(Card->TXCommands);
119 for( int i = 0; i < NUM_TX; i ++ )
121 tCommandUnit *cu = &Card->TXCommands[i].Desc.CU;
123 cu->Command = CMD_Nop|CMD_Suspend;
124 cu->Link = MM_GetPhysAddr(&Card->TXCommands[(i+1)%NUM_TX]);
127 _Write32(Card, REG_GenPtr, 0);
129 _Write16(Card, REG_Command, CU_CMD_BASE);
131 // Ensure CU is in suspend before we attempt sending
132 Card->LastTXIndex = 1;
133 Card->CurTXIndex = 1;
134 _Write32(Card, REG_GenPtr, txbase);
136 _Write16(Card, REG_Command, CU_CMD_START);
139 // Create RX Descriptors
140 for( int i = 0; i < NUM_RX; i += 2 )
142 char *base = MM_AllocDMA(1, 32, NULL);
144 Card->RXBufs[i+0] = (void*)base;
145 Card->RXBufs[i+1] = (void*)(base + 0x800);
146 for( int j = 0; j < 2; j ++ )
148 tRXBuffer *rx = Card->RXBufs[i+j];
151 // Link is populated later
152 rx->Size = RX_BUF_SIZE;
153 rx->Count = 0; // clears bit 14
154 rx->RXBufAddr = 0; // unused?
158 // NOTE: All `Link` values are relative to the RX base address
159 Uint32 rx_desc_phys = MM_GetPhysAddr(Card->RXBufs[0]);
160 for( int i = 0; i < NUM_RX-1; i ++ )
162 tRXBuffer *rx = Card->RXBufs[i];
163 rx->CU.Link = MM_GetPhysAddr(Card->RXBufs[i+1]);
165 Card->RXBufs[NUM_RX-1]->CU.Command = CMD_Suspend;
166 Card->RXBufs[NUM_RX-1]->CU.Link = 0; // link = 0, loop back
168 // Set RX Buffer base
169 _Write32(Card, REG_GenPtr, 0);
171 _Write16(Card, REG_Command, RX_CMD_ADDR_LOAD);
174 _Write32(Card, REG_GenPtr, rx_desc_phys);
176 _Write16(Card, REG_Command, RX_CMD_START);
182 int PRO100_Cleanup(void)
187 void PRO100_ReleaseRXBuf(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
190 tRXBuffer *buf = (tRXBuffer*)Data - 1;
193 for( idx = 0; idx < NUM_RX && Card->RXBufs[idx] != buf; idx ++ )
195 ASSERT(idx != NUM_RX);
197 tRXBuffer *prev = Card->RXBufs[ (idx-1+NUM_RX)%NUM_RX ];
201 prev->CU.Command &= ~CMD_Suspend;
204 _Write16(Card, REG_Command, RX_CMD_RESUME);
209 tIPStackBuffer *PRO100_WaitForPacket(void *Ptr)
215 Semaphore_Wait(&Card->RXSemaphore, 1);
216 } while( Card->RXBufs[Card->CurRXIndex]->CU.Status == 0 );
217 // Mark previous buffer as suspend (stops the RX unit running into old packets
218 Card->RXBufs[ (Card->CurRXIndex-1+NUM_RX)%NUM_RX ]->CU.Command |= CMD_Suspend;
219 tRXBuffer *buf = Card->RXBufs[Card->CurRXIndex];
220 Card->CurRXIndex = (Card->CurRXIndex+1) % NUM_RX;
222 // Return packet (freed in PRO100_ReleaseRXBuf);
223 tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(1);
224 size_t bytes = buf->Count & 0x3FFF;
225 // - actual data is just after the descriptor
226 IPStack_Buffer_AppendSubBuffer(ret, bytes, 0, buf+1, PRO100_ReleaseRXBuf, Card);
228 LOG("RX'd 0x%x bytes", bytes);
233 void PRO100_int_SetBuf(tTXCommand *TXC, int *IndexPtr, Uint32 Addr, Uint16 Len)
235 ASSERTC(*IndexPtr, <, NUM_LOCAL_TXBUFS);
237 tTXBufDesc *txb = &TXC->LocalBufs[*IndexPtr];
243 int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
247 Semaphore_Wait(&Card->TXCommandSem, 1);
249 // Acquire a command buffer
250 Mutex_Acquire(&Card->lTXCommands);
251 int txc_idx = Card->CurTXIndex;
252 Card->CurTXIndex = (Card->CurTXIndex + 1) % NUM_TX;
253 Mutex_Release(&Card->lTXCommands);
254 tTXCommand *txc = &Card->TXCommands[txc_idx];
260 size_t total_size = 0;
262 while( (buf_idx = IPStack_Buffer_GetBuffer(Buffer, buf_idx, &len, &ptr)) != -1 )
265 if( MM_GetPhysAddr(ptr) >> 32 ) {
272 ASSERTC(len, <, PAGE_SIZE);
274 // Check if buffer split is required
275 if( MM_GetPhysAddr((char*)ptr + len-1) != MM_GetPhysAddr(ptr)+len-1 )
277 // Need to split buffer
278 size_t space = PAGE_SIZE - ((tVAddr)ptr % PAGE_SIZE);
279 PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), space);
280 PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr((char*)ptr+space), len-space);
285 PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), len);
291 // Set buffer pointer
292 Card->TXBuffers[txc_idx] = Buffer;
294 txc->Desc.TBDArrayAddr = 0xFFFFFFFF;
295 txc->Desc.TCBBytes = total_size | (1 << 15);
296 txc->Desc.TXThreshold = 3; // Start transmitting after 3*8 bytes
297 txc->Desc.TBDCount = 0;
298 txc->Desc.CU.Command = CMD_Suspend|CMD_Tx;
299 txc->Desc.CU.Status = 0;
300 IPStack_Buffer_LockBuffer(Buffer);
301 // - Mark previous as not suspended
302 Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend;
304 LOG("Starting send on txc_idx=%i", txc_idx);
305 LOG("- REG_Status = %x", _Read8(Card, REG_Status));
308 // - If currently running or idle, this should not matter
309 // NOTE: Qemu describes this behavior as 'broken'
310 _Write16(Card, REG_Command, CU_CMD_RESUME);
313 IPStack_Buffer_LockBuffer(Buffer);
314 IPStack_Buffer_UnlockBuffer(Buffer);
316 LOG("- CU Status = 0x%x", txc->Desc.CU.Status);
321 void PRO100_IRQHandler(int Num, void *Ptr)
324 Uint8 status = _Read8(Card, REG_Ack);
328 _Write8(Card, REG_Ack, status);
329 LOG("status = %x", status);
331 if( status & ISR_FCP ) {
332 LOG("FCP - Flow Control Pause");
334 if( status & ISR_ER ) {
335 LOG("ER - Early Receive");
337 if( status & ISR_SWI ) {
338 LOG("SWI - Software interrupt");
340 if( status & ISR_MDI ) {
341 LOG("MDI - Management Data Interface");
344 if( status & ISR_RNR ) {
345 LOG("RNR - Recieve not ready");
347 if( status & ISR_CNA )
349 LOG("CNA - Command unit Not Active");
350 // Chase the next command buffer
351 while( Card->LastTXIndex != Card->CurTXIndex )
353 int idx = Card->LastTXIndex++;
354 // Once we hit an incomplete command, stop
355 if( !(Card->TXCommands[idx].Desc.CU.Status & CU_Status_Complete) )
357 IPStack_Buffer_UnlockBuffer( Card->TXBuffers[idx] );
358 Semaphore_Signal(&Card->TXCommandSem, 1);
360 LOG("CU Idle (%i / %i)", Card->LastTXIndex, Card->CurTXIndex);
362 if( status & ISR_FR ) {
363 LOG("FR - Frame recieved");
364 Semaphore_Signal(&Card->RXSemaphore, 1);
365 LOG("- RX signaled");
367 if( status & ISR_CX ) {
368 LOG("CX - Command executed");
372 Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *addr_len, size_t Ofs)
374 ASSERTC( *addr_len, <=, 12 );
376 Uint32 addr_data = ((EEPROM_OP_READ << *addr_len) | Ofs) << 16;
378 // Deslect chip (god knows what state it was left in)
379 _Write16( Card, REG_EEPROMCtrl, 0 );
380 _FlushWait(Card, 4); // Flush + 4us
382 _Write16( Card, REG_EEPROMCtrl, EEPROM_CTRL_CS | EEPROM_CTRL_SK );
383 _FlushWait(Card, 4); // Flush + 4us
387 // 2 preamble (0,1) + 2 command (read=1,0) + n address + 16 data
388 for( int i = (2+2+*addr_len+16); i --; )
390 Uint16 ctrl = EEPROM_CTRL_CS | ((addr_data & (1 << i)) ? EEPROM_CTRL_DI : 0);
391 _Write16( Card, REG_EEPROMCtrl, ctrl );
392 _FlushWait(Card, 4); // Flush + 4us
393 _Write16( Card, REG_EEPROMCtrl, ctrl | EEPROM_CTRL_SK );
394 _FlushWait(Card, 4); // Flush + 4us
396 ctrl = _Read16( Card, REG_EEPROMCtrl );
397 // Once the address is fully recieved, the card emits a zero bit
398 if( !(ctrl & EEPROM_CTRL_DO) && i > 16 )
400 *addr_len = *addr_len - (i - 16);
401 LOG("addr_len = %i", *addr_len);
406 data = (data << 1) | (ctrl & EEPROM_CTRL_DO ? 1 : 0);
410 _Write16( Card, REG_EEPROMCtrl, 0 );
411 _FlushWait(Card, 4); // Flush + 4us
413 LOG("Read %x from EEPROM ofs %i", data&0xFFFF, Ofs);
414 return (data & 0xFFFF);
417 static void _Write8(tCard *Card, int Ofs, Uint8 Val) {
418 //LOG("%p +%i := %02x", Card, Ofs, Val);
419 outb(Card->IOBase + Ofs, Val);
421 static void _Write16(tCard *Card, int Ofs, Uint16 Val) {
422 //LOG("%p +%i := %04x", Card, Ofs, Val);
423 ASSERT( !(Ofs & 1) );
424 outw(Card->IOBase + Ofs, Val);
426 static void _Write32(tCard *Card, int Ofs, Uint32 Val) {
427 //LOG("%p +%i := %08x", Card, Ofs, Val);
428 ASSERT( !(Ofs & 3) );
429 outd(Card->IOBase + Ofs, Val);
431 static Uint8 _Read8(tCard *Card, int Ofs) {
432 Uint8 rv = inb(Card->IOBase + Ofs);
433 //LOG("%p +%i == %02x", Card, Ofs, rv);
436 static Uint16 _Read16(tCard *Card, int Ofs) {
437 ASSERT( !(Ofs & 1) );
438 Uint16 rv = inw(Card->IOBase + Ofs);
439 //LOG("%p +%i == %04x", Card, Ofs, rv);
442 //static Uint32 _Read32(tCard *Card, int Ofs) { return ind(Card->IOBase + Ofs); }
444 static void _FlushWait(tCard *Card, int Delay)
446 _Read16( Card, REG_Status );
449 Time_MicroSleep(Delay);