Modules/PRO100 - Real hardware testing
[tpg/acess2.git] / KernelLand / Modules / Network / PRO100 / main.c
1 /*
2  * Acess2 PRO/100 Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * main.c
6  * - Driver core
7  *
8  * 8255x (Intel 8255x 10/100 Mbps Ethernet Controller Family)
9  */
10 #define DEBUG   1
11 #include <acess.h>
12 #include <IPStack/include/adapters_api.h>
13 #include <modules.h>
14 #include <drv_pci.h>
15 #include <timers.h>
16 #include "pro100.h"
17
18 // === CONSTANTS ===
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
23         };
24 static const int        ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]);
25
26 // === PROTOTYPES ===
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);
33
34 Uint16  PRO100_int_ReadEEPROM(tCard *Card, Uint8 *AddrLen, size_t Ofs);
35
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);
43
44 // === GLOBALS ===
45 MODULE_DEFINE(0, 0x100, PRO100, PRO100_Install, PRO100_Cleanup, "IPStack", NULL);
46 tIPStack_AdapterType    gPRO100_AdapterType = {
47         .Name = "PRO/100",
48         .Type = ADAPTERTYPE_ETHERNET_100M,
49         .Flags = ADAPTERFLAG_OFFLOAD_MAC,       
50         .SendPacket = PRO100_SendPacket,
51         .WaitForPacket = PRO100_WaitForPacket
52 };
53 tCard   gaPRO100_StaticCards[NUM_STATIC_CARDS];
54
55 // === CODE ===
56 int PRO100_Install(char **Arguments)
57 {
58          int    cardidx = 0;
59         for( int i = 0; i < ciNumSupportedCards; i ++ )
60         {
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++ )
65                 {
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);
70
71                         PCI_SetCommand(pciid, PCI_CMD_IOENABLE|PCI_CMD_BUSMASTER, 0);
72                         
73                         tCard   *card;
74                         if( cardidx < NUM_STATIC_CARDS ) {
75                                 card = &gaPRO100_StaticCards[cardidx++];
76                         }
77                         else {
78                                 card = malloc(sizeof(tCard));
79                         }
80
81                         card->IOBase = iobase;
82                         //card->MMIO = MM_MapHWPages(mmiobase, 1);
83                         IRQ_AddHandler(irq, PRO100_IRQHandler, card); 
84                         
85                         // TODO: Error check
86                         PRO100_InitCard(card);
87                         
88                         IPStack_Adapter_Add(&gPRO100_AdapterType, card, card->MAC.Bytes);
89                 }
90         }
91         return MODULE_ERR_OK;
92 }
93
94 int PRO100_InitCard(tCard *Card)
95 {
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");
99
100         // Card reset
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
105
106         // Read MAC address
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);
111
112         // Set interrupt mask
113         _Write8(Card, REG_IntMask, 0);
114
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 ++ )
120         {
121                 tCommandUnit    *cu = &Card->TXCommands[i].Desc.CU;
122                 cu->Status = 0;
123                 cu->Command = CMD_Nop|CMD_Suspend;
124                 cu->Link = MM_GetPhysAddr(&Card->TXCommands[(i+1)%NUM_TX]);
125         }
126         
127         _Write32(Card, REG_GenPtr, 0);
128         _FlushWait(Card, 4);
129         _Write16(Card, REG_Command, CU_CMD_BASE);
130         _FlushWait(Card, 4);
131         // Ensure CU is in suspend before we attempt sending
132         Card->LastTXIndex = 1;
133         Card->CurTXIndex = 1;
134         _Write32(Card, REG_GenPtr, txbase);
135         _FlushWait(Card, 4);
136         _Write16(Card, REG_Command, CU_CMD_START);
137         _FlushWait(Card, 4);
138
139         // Create RX Descriptors
140         for( int i = 0; i < NUM_RX; i += 2 )
141         {
142                 char    *base = MM_AllocDMA(1, 32, NULL);
143                 ASSERT(base);
144                 Card->RXBufs[i+0] = (void*)base;
145                 Card->RXBufs[i+1] = (void*)(base + 0x800);
146                 for( int j = 0; j < 2; j ++ )
147                 {
148                         tRXBuffer       *rx = Card->RXBufs[i+j];
149                         rx->CU.Status = 0;
150                         rx->CU.Command = 0;
151                         // Link is populated later
152                         rx->Size = RX_BUF_SIZE;
153                         rx->Count = 0;  // clears bit 14
154                         rx->RXBufAddr = 0;      // unused?
155                 }
156         }
157
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 ++ )
161         {
162                 tRXBuffer       *rx = Card->RXBufs[i];
163                 rx->CU.Link = MM_GetPhysAddr(Card->RXBufs[i+1]);
164         }
165         Card->RXBufs[NUM_RX-1]->CU.Command = CMD_Suspend;
166         Card->RXBufs[NUM_RX-1]->CU.Link = 0;    // link = 0, loop back
167         
168         // Set RX Buffer base
169         _Write32(Card, REG_GenPtr, 0);
170         _FlushWait(Card, 4);
171         _Write16(Card, REG_Command, RX_CMD_ADDR_LOAD);
172         _FlushWait(Card, 4);
173         
174         _Write32(Card, REG_GenPtr, rx_desc_phys);
175         _FlushWait(Card, 4);
176         _Write16(Card, REG_Command, RX_CMD_START);
177         _FlushWait(Card, 4);
178
179         return 0;
180 }
181
182 int PRO100_Cleanup(void)
183 {
184         return 0;
185 }
186
187 void PRO100_ReleaseRXBuf(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
188 {
189         tCard   *Card = Arg;
190         tRXBuffer       *buf = (tRXBuffer*)Data - 1;
191
192          int    idx;
193         for( idx = 0; idx < NUM_RX && Card->RXBufs[idx] != buf; idx ++ )
194                 ;
195         ASSERT(idx != NUM_RX);
196
197         tRXBuffer       *prev = Card->RXBufs[ (idx-1+NUM_RX)%NUM_RX ];
198         buf->CU.Status = 0;
199         buf->CU.Command = 0;
200         buf->Count = 0;
201         prev->CU.Command &= ~CMD_Suspend;
202         
203         // Resume
204         _Write16(Card, REG_Command, RX_CMD_RESUME);
205         _FlushWait(Card, 4);
206 }
207
208
209 tIPStackBuffer *PRO100_WaitForPacket(void *Ptr)
210 {
211         tCard   *Card = Ptr;
212         
213         // Wait for a packet
214         do {
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;
221         
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);
227
228         LOG("RX'd 0x%x bytes", bytes);
229
230         return ret;
231 }
232
233 void PRO100_int_SetBuf(tTXCommand *TXC, int *IndexPtr, Uint32 Addr, Uint16 Len)
234 {
235         ASSERTC(*IndexPtr, <, NUM_LOCAL_TXBUFS);
236         
237         tTXBufDesc      *txb = &TXC->LocalBufs[*IndexPtr];
238         txb->Addr = Addr;
239         txb->Len = Len;
240         (*IndexPtr) ++;
241 }
242
243 int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
244 {
245         tCard   *Card = Ptr;
246
247         Semaphore_Wait(&Card->TXCommandSem, 1);
248
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];
255
256         // Populate
257          int    txb_idx = 0;
258         const void      *ptr;
259         size_t  len;
260         size_t  total_size = 0;
261          int    buf_idx = -1;
262         while( (buf_idx = IPStack_Buffer_GetBuffer(Buffer, buf_idx, &len, &ptr)) != -1 ) 
263         {
264                 #if PHYS_BITS > 32
265                 if( MM_GetPhysAddr(ptr) >> 32 ) {
266                         // Need to bounce
267                         TODO();
268                         continue ;
269                 }
270                 #endif
271                 
272                 ASSERTC(len, <, PAGE_SIZE);
273                 
274                 // Check if buffer split is required
275                 if( MM_GetPhysAddr((char*)ptr + len-1) != MM_GetPhysAddr(ptr)+len-1 )
276                 {
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);
281                 }
282                 else
283                 {
284                         // Single buffer
285                         PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), len);
286                 }
287                 
288                 total_size += len;
289         }
290
291         // Set buffer pointer
292         Card->TXBuffers[txc_idx] = Buffer;
293         // Mark as usable
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;
303
304         LOG("Starting send on txc_idx=%i", txc_idx);
305         LOG("- REG_Status = %x", _Read8(Card, REG_Status));
306
307         // And dispatch
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);
311         _FlushWait(Card, 4);
312
313         IPStack_Buffer_LockBuffer(Buffer);
314         IPStack_Buffer_UnlockBuffer(Buffer);
315
316         LOG("- CU Status = 0x%x", txc->Desc.CU.Status);
317
318         return 0;
319 }
320
321 void PRO100_IRQHandler(int Num, void *Ptr)
322 {
323         tCard   *Card = Ptr;
324         Uint8   status = _Read8(Card, REG_Ack);
325         
326         if( !status )
327                 return ;
328         _Write8(Card, REG_Ack, status);
329         LOG("status = %x", status);
330
331         if( status & ISR_FCP ) {
332                 LOG("FCP - Flow Control Pause");
333         }
334         if( status & ISR_ER ) {
335                 LOG("ER - Early Receive");
336         }
337         if( status & ISR_SWI ) {
338                 LOG("SWI - Software interrupt");
339         }
340         if( status & ISR_MDI ) {
341                 LOG("MDI - Management Data Interface");
342         }
343
344         if( status & ISR_RNR ) {
345                 LOG("RNR - Recieve not ready");
346         }
347         if( status & ISR_CNA )
348         {
349                 LOG("CNA - Command unit Not Active");
350                 // Chase the next command buffer
351                 while( Card->LastTXIndex != Card->CurTXIndex )
352                 {
353                          int    idx = Card->LastTXIndex++;
354                         // Once we hit an incomplete command, stop
355                         if( !(Card->TXCommands[idx].Desc.CU.Status & CU_Status_Complete) )
356                                 break ;
357                         IPStack_Buffer_UnlockBuffer( Card->TXBuffers[idx] );
358                         Semaphore_Signal(&Card->TXCommandSem, 1);
359                 }
360                 LOG("CU Idle (%i / %i)", Card->LastTXIndex, Card->CurTXIndex);
361         }
362         if( status & ISR_FR ) {
363                 LOG("FR - Frame recieved");
364                 Semaphore_Signal(&Card->RXSemaphore, 1);
365                 LOG("- RX signaled");
366         }
367         if( status & ISR_CX ) {
368                 LOG("CX - Command executed");
369         }
370 }
371
372 Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *addr_len, size_t Ofs)
373 {
374         ASSERTC( *addr_len, <=, 12 );
375         
376         Uint32  addr_data = ((EEPROM_OP_READ << *addr_len) | Ofs) << 16;
377
378         // Deslect chip (god knows what state it was left in)
379         _Write16( Card, REG_EEPROMCtrl, 0 );
380         _FlushWait(Card, 4);    // Flush + 4us
381         // Raise CS
382         _Write16( Card, REG_EEPROMCtrl, EEPROM_CTRL_CS | EEPROM_CTRL_SK );
383         _FlushWait(Card, 4);    // Flush + 4us
384
385         Uint32  data = 0;       
386
387         // 2 preamble (0,1) + 2 command (read=1,0) + n address + 16 data
388         for( int i = (2+2+*addr_len+16); i --; )
389         {
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
395                 
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 )
399                 {
400                         *addr_len = *addr_len - (i - 16);
401                         LOG("addr_len = %i", *addr_len);
402                         
403                         i = 16;
404                 }
405                 
406                 data = (data << 1) | (ctrl & EEPROM_CTRL_DO ? 1 : 0);
407         }
408
409         // Deslect chip
410         _Write16( Card, REG_EEPROMCtrl, 0 );
411         _FlushWait(Card, 4);    // Flush + 4us
412
413         LOG("Read %x from EEPROM ofs %i", data&0xFFFF, Ofs);
414         return (data & 0xFFFF);
415 }
416
417 static void _Write8(tCard *Card, int Ofs, Uint8 Val) {
418         //LOG("%p +%i := %02x", Card, Ofs, Val);
419         outb(Card->IOBase + Ofs, Val);
420 }
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);
425 }
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);
430 }
431 static Uint8 _Read8(tCard *Card, int Ofs) {
432         Uint8 rv = inb(Card->IOBase + Ofs);
433         //LOG("%p +%i == %02x", Card, Ofs, rv);
434         return rv;
435 }
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);
440         return rv;
441 }
442 //static Uint32 _Read32(tCard *Card, int Ofs) { return ind(Card->IOBase + Ofs); }
443
444 static void _FlushWait(tCard *Card, int Delay)
445 {
446         _Read16( Card, REG_Status );
447         if(Delay > 0)
448         {
449                 Time_MicroSleep(Delay);
450         }
451 }
452

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