7a017ebf6af5d6d1fcfbfc0f8085ac9afafbaa9c
[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  * Built with reference to the linux e100 driver (drivers/net/ethernet/intel/e100.c)
9  * 82559-fast-ethernet-multifunciton-pci-datasheet.pdf
10  */
11 #define DEBUG   1
12 #include <acess.h>
13 #include <IPStack/include/adapters_api.h>
14 #include <modules.h>
15 #include <drv_pci.h>
16 #include <timers.h>
17 #include "pro100.h"
18
19 // === CONSTANTS ===
20 #define NUM_STATIC_CARDS        2
21 static const Uint16     caSupportedCards[][2] = {
22         {0x8086, 0x103D},       // prelude's card
23         {0x8086, 0x1209},       // qemu's i82559 emulation
24         };
25 static const int        ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]);
26
27 // === PROTOTYPES ===
28  int    PRO100_Install(char **Arguments);
29  int    PRO100_InitCard(tCard *Card);
30  int    PRO100_Cleanup(void);
31 tIPStackBuffer  *PRO100_WaitForPacket(void *Ptr);
32  int    PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
33 void    PRO100_IRQHandler(int Num, void *Ptr);
34
35 Uint16  PRO100_int_ReadEEPROM(tCard *Card, Uint8 *AddrLen, size_t Ofs);
36
37 static void     _Write8(tCard *Card, int Ofs, Uint8 Val);
38 static void     _Write16(tCard *Card, int Ofs, Uint16 Val);
39 static void     _Write32(tCard *Card, int Ofs, Uint32 Val);
40 static Uint8    _Read8(tCard *Card, int Ofs);
41 static Uint16   _Read16(tCard *Card, int Ofs);
42 //static Uint32 _Read32(tCard *Card, int Ofs);
43 static void     _FlushWait(tCard *Card, int Delay);
44
45 // === GLOBALS ===
46 MODULE_DEFINE(0, 0x100, PRO100, PRO100_Install, PRO100_Cleanup, "IPStack", NULL);
47 tIPStack_AdapterType    gPRO100_AdapterType = {
48         .Name = "PRO/100",
49         .Type = ADAPTERTYPE_ETHERNET_100M,
50         .Flags = 0,     
51         .SendPacket = PRO100_SendPacket,
52         .WaitForPacket = PRO100_WaitForPacket
53 };
54 tCard   gaPRO100_StaticCards[NUM_STATIC_CARDS];
55
56 // === CODE ===
57 int PRO100_Install(char **Arguments)
58 {
59          int    cardidx = 0;
60         for( int i = 0; i < ciNumSupportedCards; i ++ )
61         {
62                 const Uint16    *ven_dev = caSupportedCards[i];
63                 LOG("Checking %04x:%04x: %i reported", ven_dev[0], ven_dev[1],
64                         PCI_CountDevices(ven_dev[0], ven_dev[1]));
65                 for( int idx = 0, pciid = -1; -1 != (pciid = PCI_GetDevice(ven_dev[0], ven_dev[1], idx)); idx++ )
66                 {
67                         Uint8   irq = PCI_GetIRQ(pciid);
68                         Uint32  mmiobase = PCI_GetValidBAR(pciid, 0, PCI_BARTYPE_MEM32);
69                         Uint16  iobase = PCI_GetValidBAR(pciid, 1, PCI_BARTYPE_IO);
70                         LOG("IO Base = %x, MMIOBase = %x", iobase, mmiobase);
71
72                         PCI_SetCommand(pciid, PCI_CMD_IOENABLE|PCI_CMD_BUSMASTER, 0);
73                         
74                         tCard   *card;
75                         if( cardidx < NUM_STATIC_CARDS ) {
76                                 card = &gaPRO100_StaticCards[cardidx++];
77                         }
78                         else {
79                                 card = malloc(sizeof(tCard));
80                         }
81
82                         card->IOBase = iobase;
83                         //card->MMIO = MM_MapHWPages(mmiobase, 1);
84                         IRQ_AddHandler(irq, PRO100_IRQHandler, card); 
85                         
86                         // TODO: Error check
87                         PRO100_InitCard(card);
88                         
89                         IPStack_Adapter_Add(&gPRO100_AdapterType, card, card->MAC.Bytes);
90                 }
91         }
92         return MODULE_ERR_OK;
93 }
94
95 int PRO100_InitCard(tCard *Card)
96 {
97         // Initialise structures
98         Semaphore_Init(&Card->TXCommandSem, NUM_TX, NUM_TX, "PRO100", "Command Buffers");
99         Semaphore_Init(&Card->RXSemaphore, 0, NUM_RX, "PRO100", "Receive");
100
101         // Card reset
102         _Write32(Card, REG_Port, PORT_SELECTIVERESET);
103         _FlushWait(Card, 20);   // - Write Flush, wait 20us
104         _Write32(Card, REG_Port, PORT_SOFTWARERESET);
105         _FlushWait(Card, 20);   // - Write Flush, wait 20us
106
107         // Read MAC address
108         Uint8   addr_len = 8;   // default to 8, updated on first read
109         Card->MAC.Words[0] = PRO100_int_ReadEEPROM(Card, &addr_len, 0);
110         Card->MAC.Words[1] = PRO100_int_ReadEEPROM(Card, &addr_len, 1);
111         Card->MAC.Words[2] = PRO100_int_ReadEEPROM(Card, &addr_len, 2);
112
113         // Set interrupt mask
114         _Write8(Card, REG_IntMask, 0);
115
116         // Prepare Command Unit
117         Card->TXCommands = MM_AllocDMA(1, 32, NULL);
118         Uint32  txbase = MM_GetPhysAddr(Card->TXCommands);
119         ASSERT(Card->TXCommands);
120         for( int i = 0; i < NUM_TX; i ++ )
121         {
122                 tCommandUnit    *cu = &Card->TXCommands[i].Desc.CU;
123                 cu->Status = 0;
124                 cu->Command = CMD_Nop|CMD_Suspend;
125                 cu->Link = MM_GetPhysAddr(&Card->TXCommands[(i+1)%NUM_TX]) - txbase;
126         }
127         
128         _Write32(Card, REG_GenPtr, txbase);
129         _Write16(Card, REG_Command, CU_CMD_BASE);
130         // Ensure CU is in suspend before we attempt sending
131         Card->LastTXIndex = 1;
132         Card->CurTXIndex = 1;
133         _Write32(Card, REG_GenPtr, 0);
134         _Write16(Card, REG_Command, CU_CMD_START);
135
136         // Create RX Descriptors
137         for( int i = 0; i < NUM_RX; i += 2 )
138         {
139                 char    *base = MM_AllocDMA(1, 32, NULL);
140                 ASSERT(base);
141                 Card->RXBufs[i+0] = (void*)base;
142                 Card->RXBufs[i+1] = (void*)(base + 0x800);
143                 for( int j = 0; j < 2; j ++ )
144                 {
145                         tRXBuffer       *rx = Card->RXBufs[i+j];
146                         rx->CU.Status = 0;
147                         rx->CU.Command = 0;
148                         // Link is populated later
149                         rx->Size = RX_BUF_SIZE;
150                         rx->RXBufAddr = 0;      // unused?
151                 }
152         }
153
154         // NOTE: All `Link` values are relative to the RX base address  
155         Uint32  rx_desc_phys = MM_GetPhysAddr(Card->RXBufs[0]);
156         for( int i = 0; i < NUM_RX-1; i ++ )
157         {
158                 tRXBuffer       *rx = Card->RXBufs[i];
159                 rx->CU.Link = MM_GetPhysAddr(Card->RXBufs[i+1]) - rx_desc_phys;
160         }
161         Card->RXBufs[NUM_RX-1]->CU.Command = CMD_Suspend;
162         Card->RXBufs[NUM_RX-1]->CU.Link = 0;    // link = 0, loop back
163         
164         // Set RX Buffer base
165         _Write32(Card, REG_GenPtr, rx_desc_phys);
166         _Write16(Card, REG_Command, RX_CMD_ADDR_LOAD);
167         
168         _Write32(Card, REG_GenPtr, 0);
169         _Write16(Card, REG_Command, RX_CMD_START);
170
171         return 0;
172 }
173
174 int PRO100_Cleanup(void)
175 {
176         return 0;
177 }
178
179 void PRO100_ReleaseRXBuf(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
180 {
181         tCard   *Card = Arg;
182         tRXBuffer       *buf = (tRXBuffer*)Data - 1;
183
184          int    idx;
185         for( idx = 0; idx < NUM_RX && Card->RXBufs[idx] != buf; idx ++ )
186                 ;
187         ASSERT(idx != NUM_RX);
188
189         tRXBuffer       *prev = Card->RXBufs[ (idx-1+NUM_RX)%NUM_RX ];
190         buf->CU.Status = 0;
191         buf->CU.Command = 0;
192         prev->CU.Command &= ~CMD_Suspend;
193         
194         // Resume
195         _Write16(Card, REG_Command, RX_CMD_RESUME);
196 }
197
198
199 tIPStackBuffer *PRO100_WaitForPacket(void *Ptr)
200 {
201         tCard   *Card = Ptr;
202         // Wait for a packet
203         do {
204                 Semaphore_Wait(&Card->RXSemaphore, 1);
205         } while( Card->RXBufs[Card->CurRXIndex]->CU.Status == 0 );
206         // Mark previous buffer as suspend (stops the RX unit running into old packets
207         Card->RXBufs[ (Card->CurRXIndex-1+NUM_RX)%NUM_RX ]->CU.Command |= CMD_Suspend;
208         tRXBuffer *buf = Card->RXBufs[Card->CurRXIndex];
209         Card->CurRXIndex = (Card->CurRXIndex+1) % NUM_RX;
210         
211         // Return packet (freed in PRO100_ReleaseRXBuf);
212         tIPStackBuffer  *ret = IPStack_Buffer_CreateBuffer(1);
213         // - actual data is just after the descriptor
214         IPStack_Buffer_AppendSubBuffer(ret, buf->Count, 0, buf+1, PRO100_ReleaseRXBuf, Card);
215         
216         return ret;
217 }
218
219 void PRO100_int_SetBuf(tTXCommand *TXC, int *IndexPtr, Uint32 Addr, Uint16 Len)
220 {
221         ASSERTC(*IndexPtr, <, NUM_LOCAL_TXBUFS);
222         
223         tTXBufDesc      *txb = &TXC->LocalBufs[*IndexPtr];
224         txb->Addr = Addr;
225         txb->Len = Len;
226         (*IndexPtr) ++;
227 }
228
229 int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
230 {
231         tCard   *Card = Ptr;
232
233         Semaphore_Wait(&Card->TXCommandSem, 1);
234
235         // Acquire a command buffer
236         Mutex_Acquire(&Card->lTXCommands);
237         int txc_idx = Card->CurTXIndex;
238         Card->CurTXIndex = (Card->CurTXIndex + 1) % NUM_TX;
239         Mutex_Release(&Card->lTXCommands);
240         tTXCommand      *txc = &Card->TXCommands[txc_idx];
241
242         // Populate
243          int    txb_idx = 0;
244         const void      *ptr;
245         size_t  len;
246         size_t  total_size = 0;
247          int    buf_idx = -1;
248         while( (buf_idx = IPStack_Buffer_GetBuffer(Buffer, buf_idx, &len, &ptr)) != -1 ) 
249         {
250                 #if PHYS_BITS > 32
251                 if( MM_GetPhysAddr(ptr) >> 32 ) {
252                         // Need to bounce
253                         TODO();
254                         continue ;
255                 }
256                 #endif
257                 
258                 ASSERTC(len, <, PAGE_SIZE);
259                 
260                 // Check if buffer split is required
261                 if( MM_GetPhysAddr((char*)ptr + len-1) != MM_GetPhysAddr(ptr)+len-1 )
262                 {
263                         // Need to split buffer
264                         size_t  space = PAGE_SIZE - ((tVAddr)ptr % PAGE_SIZE);
265                         PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), space);
266                         PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr((char*)ptr+space), len-space);
267                 }
268                 else
269                 {
270                         // Single buffer
271                         PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), len);
272                 }
273                 
274                 total_size += len;
275         }
276
277         // Set buffer pointer
278         Card->TXBuffers[txc_idx] = Buffer;
279         // Mark as usable
280         txc->Desc.TBDArrayAddr = 0xFFFFFFFF;
281         txc->Desc.TCBBytes = total_size;
282         txc->Desc.TXThreshold = 0;      // TODO: What does this do on RHW?
283         txc->Desc.TBDCount = 0;
284         txc->Desc.CU.Command = CMD_Suspend|CMD_Tx;
285         // - Mark previous as not suspended
286         Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend;
287
288         IPStack_Buffer_LockBuffer(Buffer);
289
290         // And dispatch
291         // - If currently running or idle, this should not matter
292         // NOTE: Qemu describes this behavior as 'broken'
293         _Write16(Card, REG_Command, CU_CMD_RESUME);
294
295         IPStack_Buffer_LockBuffer(Buffer);
296         IPStack_Buffer_UnlockBuffer(Buffer);
297
298         return 0;
299 }
300
301 void PRO100_IRQHandler(int Num, void *Ptr)
302 {
303         tCard   *Card = Ptr;
304         Uint8   status = _Read8(Card, REG_Ack);
305         
306         if( !status )
307                 return ;
308         
309         _Write8(Card, REG_Ack, status);
310         LOG("status = %x", status);
311         if( status & ISR_FR ) {
312                 LOG("FR");
313                 Semaphore_Signal(&Card->RXSemaphore, 1);
314         }
315         
316         // CU Idle
317         if( status & ISR_CNA )
318         {
319                 // Chase the next command buffer
320                 while( Card->LastTXIndex != Card->CurTXIndex )
321                 {
322                          int    idx = Card->LastTXIndex++;
323                         // Once we hit an incomplete command, stop
324                         if( !(Card->TXCommands[idx].Desc.CU.Status & CU_Status_Complete) )
325                                 break ;
326                         IPStack_Buffer_UnlockBuffer( Card->TXBuffers[idx] );
327                         Semaphore_Signal(&Card->TXCommandSem, 1);
328                 }
329                 LOG("CU Idle (%i / %i)", Card->LastTXIndex, Card->CurTXIndex);
330         }
331 }
332
333 Uint16 PRO100_int_ReadEEPROM(tCard *Card, Uint8 *addr_len, size_t Ofs)
334 {
335         ASSERTC( *addr_len, <=, 12 );
336         
337         Uint32  addr_data = ((EEPROM_OP_READ << *addr_len) | Ofs) << 16;
338
339         // Deslect chip (god knows what state it was left in)
340         _Write16( Card, REG_EEPROMCtrl, 0 );
341         _FlushWait(Card, 4);    // Flush + 4us
342         // Raise CS
343         _Write16( Card, REG_EEPROMCtrl, EEPROM_CTRL_CS | EEPROM_CTRL_SK );
344         _FlushWait(Card, 4);    // Flush + 4us
345
346         Uint32  data = 0;       
347
348         // 2 preamble (0,1) + 2 command (read=1,0) + n address + 16 data
349         for( int i = (2+2+*addr_len+16); i --; )
350         {
351                 Uint16  ctrl = EEPROM_CTRL_CS | ((addr_data & (1 << i)) ? EEPROM_CTRL_DI : 0);
352                 _Write16( Card, REG_EEPROMCtrl, ctrl );
353                 _FlushWait(Card, 4);    // Flush + 4us
354                 _Write16( Card, REG_EEPROMCtrl, ctrl | EEPROM_CTRL_SK );
355                 _FlushWait(Card, 4);    // Flush + 4us
356                 
357                 ctrl = _Read16( Card, REG_EEPROMCtrl );
358                 // Once the address is fully recieved, the card emits a zero bit
359                 if( !(ctrl & EEPROM_CTRL_DO) && i > 16 )
360                 {
361                         *addr_len = *addr_len - (i - 16);
362                         LOG("addr_len = %i", *addr_len);
363                         
364                         i = 16;
365                 }
366                 
367                 data = (data << 1) | (ctrl & EEPROM_CTRL_DO ? 1 : 0);
368         }
369
370         // Deslect chip
371         _Write16( Card, REG_EEPROMCtrl, 0 );
372         _FlushWait(Card, 4);    // Flush + 4us
373
374         LOG("Read %x from EEPROM ofs %i", data&0xFFFF, Ofs);
375         return (data & 0xFFFF);
376 }
377
378 static void _Write8(tCard *Card, int Ofs, Uint8 Val) {
379         //LOG("%p +%i := %02x", Card, Ofs, Val);
380         outb(Card->IOBase + Ofs, Val);
381 }
382 static void _Write16(tCard *Card, int Ofs, Uint16 Val) {
383         //LOG("%p +%i := %04x", Card, Ofs, Val);
384         ASSERT( !(Ofs & 1) );
385         outw(Card->IOBase + Ofs, Val);
386 }
387 static void _Write32(tCard *Card, int Ofs, Uint32 Val) {
388         //LOG("%p +%i := %08x", Card, Ofs, Val);
389         ASSERT( !(Ofs & 3) );
390         outd(Card->IOBase + Ofs, Val);
391 }
392 static Uint8 _Read8(tCard *Card, int Ofs) {
393         Uint8 rv = inb(Card->IOBase + Ofs);
394         //LOG("%p +%i == %02x", Card, Ofs, rv);
395         return rv;
396 }
397 static Uint16 _Read16(tCard *Card, int Ofs) {
398         ASSERT( !(Ofs & 1) );
399         Uint16 rv = inw(Card->IOBase + Ofs);
400         //LOG("%p +%i == %04x", Card, Ofs, rv);
401         return rv;
402 }
403 //static Uint32 _Read32(tCard *Card, int Ofs) { return ind(Card->IOBase + Ofs); }
404
405 static void _FlushWait(tCard *Card, int Delay)
406 {
407         _Read16( Card, REG_Status );
408         if(Delay > 0)
409         {
410                 Time_MicroSleep(Delay);
411         }
412 }
413

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