e777e6066182f70f6d32119b9af522fa904e40ff
[tpg/acess2.git] / KernelLand / Modules / Network / PCnetFAST3 / pcnet-fast3.c
1 /*
2  * Acess2 PCnet-FAST III Driver
3  * - By John Hodge (thePowersGang)
4  */
5 #define DEBUG   1
6 #define VERSION ((1<<8)|0)
7 #include <acess.h>
8 #include <modules.h>
9 #include <drv_pci.h>
10 #include <semaphore.h>
11 #include <IPStack/include/adapters_api.h>
12 #include "hw.h"
13
14 // === CONSTANTS ===
15 #define VENDOR_ID       0x1022
16 #define DEVICE_ID       0x2000
17 #define TLEN_LOG2       6       // 64
18 #define RLEN_LOG2       7
19 #define TLEN    (1 << TLEN_LOG2)
20 #define RLEN    (1 << RLEN_LOG2)
21 #define RXBUFLEN        128     // 128*128 = 16K total RX buffer
22 #define RXBUF_PER_PAGE  (PAGE_SIZE/RXBUFLEN)
23 #define NUM_RXBUF_PAGES ((RLEN*RXBUFLEN)/PAGE_SIZE)
24
25 // === TYPES ===
26 typedef struct sCard
27 {
28         Uint16  IOBase;
29         Uint8   IRQ;
30
31         tPAddr  TxQueuePhys;
32         tTxDesc_3       *TxQueue;
33         void    *TxQueueBuffers[TLEN];  // Pointer to the tIPStackBuffer (STP only)
34
35         tMutex  lTxPos;
36         tSemaphore      TxDescSem;
37          int    FirstUsedTxD;
38          int    FirstFreeTx;
39         
40         tSemaphore      ReadSemaphore;  
41         tMutex  lRxPos;
42          int    RxPos;
43         tPAddr  RxQueuePhys;
44         tRxDesc_3       *RxQueue;
45         void    *RxBuffers[NUM_RXBUF_PAGES];    // Pages
46         
47         Uint8   MacAddr[6];
48         void    *IPStackHandle;
49 }       tCard;
50
51 // === PROTOTYPES ===
52  int    PCnet3_Install(char **Options);
53  int    PCnet3_Cleanup(void);
54
55 tIPStackBuffer  *PCnet3_WaitForPacket(void *Ptr);
56  int    PCnet3_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
57
58  int    PCnet3_int_InitCard(tCard *Card);
59 void    PCnet3_IRQHandler(int Num, void *Ptr);
60 void    PCnet3_ReleaseRxD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data);
61
62 static Uint16   _ReadCSR(tCard *Card, Uint8 Reg);
63 static void     _WriteCSR(tCard *Card, Uint8 Reg, Uint16 Value);
64 static Uint16   _ReadBCR(tCard *Card, Uint8 Reg);
65 static void     _WriteBCR(tCard *Card, Uint8 Reg, Uint16 Value);
66
67 // === GLOBALS ===
68 MODULE_DEFINE(0, VERSION, Network_PCnetFAST3, PCnet3_Install, PCnet3_Cleanup, "IPStack", NULL);
69 tIPStack_AdapterType    gPCnet3_AdapterType = {
70         .Name = "PCnet-FAST III",
71         .Type = ADAPTERTYPE_ETHERNET_100M,
72         //.Flags = ADAPTERFLAG_OFFLOAD_MAC,
73         .Flags = 0,
74         .SendPacket = PCnet3_SendPacket,
75         .WaitForPacket = PCnet3_WaitForPacket
76 };
77  int    giPCnet3_CardCount;
78 tCard   *gaPCnet3_Cards;
79 // - Init
80 tInitBlock32    gPCnet3_StaticInitBlock;
81 tInitBlock32    *gpPCnet3_InitBlock;
82
83 // === CODE ===
84 /**
85  * \brief Installs the PCnet3 Driver
86  */
87 int PCnet3_Install(char **Options)
88 {
89          int    id = -1;
90          int    i = 0;
91         Uint16  base;
92         tCard   *card;
93         
94         giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
95         Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount);
96         
97         if( giPCnet3_CardCount == 0 )   return MODULE_ERR_NOTNEEDED;
98
99         gpPCnet3_InitBlock = &gPCnet3_StaticInitBlock;
100         // TODO: Edge case bug here with the block on the end of a page
101         if( MM_GetPhysAddr(gpPCnet3_InitBlock) + sizeof(tInitBlock32) != MM_GetPhysAddr(gpPCnet3_InitBlock+1)
102         #if PHYS_BITS > 32
103                 ||  MM_GetPhysAddr(gpPCnet3_InitBlock) > (1ULL<<32)
104         #endif
105                 )
106         {
107                 // allocate
108                 Log_Error("PCnet3", "TODO: Support 64-bit init / spanning init");
109                 return MODULE_ERR_MISC;
110         }
111         
112         gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) );
113         
114         while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 )
115         {
116                 // Set up card addresses
117                 // - BAR0: IO base address
118                 // - BAR1: MMIO base address
119                 card = &gaPCnet3_Cards[i];
120                 base = PCI_GetBAR( id, 0 );
121                 if( !(base & 1) ) {
122                         Log_Warning("PCnet3", "Driver does not support MMIO, skipping card");
123                         card->IOBase = 0;
124                         card->IRQ = 0;
125                         continue ;
126                 }
127                 base &= ~1;
128                 card->IOBase = base;
129                 card->IRQ = PCI_GetIRQ( id );
130
131                 // Switch the card into DWord mode
132                 // - TODO: Should the value of RAP matter here?
133                 outd(card->IOBase + REG_RDP, 0);
134
135                 // Get MAC address
136                 Uint32  macword;
137                 macword = ind(card->IOBase + REG_APROM0);
138                 card->MacAddr[0] = macword & 0xFF;
139                 card->MacAddr[1] = macword >> 8;
140                 card->MacAddr[2] = macword >> 16;
141                 card->MacAddr[3] = macword >> 24;
142                 macword = ind(card->IOBase + REG_APROM4);
143                 card->MacAddr[4] = macword & 0xFF;
144                 card->MacAddr[5] = macword >> 8;
145
146                 // Install IRQ Handler
147                 IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler, card);
148                 
149                 // Initialise the card state
150                 PCnet3_int_InitCard(card);
151
152                 // Register
153                 card->IPStackHandle = IPStack_Adapter_Add(&gPCnet3_AdapterType, card, card->MacAddr);
154                 
155                 i ++;
156         }
157
158         if( gpPCnet3_InitBlock != &gPCnet3_StaticInitBlock ) {
159                 MM_UnmapHWPages( (tVAddr)gpPCnet3_InitBlock, 1 );
160         }
161         
162         return MODULE_ERR_OK;
163 }
164
165 int PCnet3_Cleanup(void)
166 {
167         // TODO: Kill IPStack adapters and clean up
168         return -1;
169 }
170
171 // --- Root Functions ---
172 tIPStackBuffer *PCnet3_WaitForPacket(void *Ptr)
173 {
174         tCard   *card = Ptr;
175
176         ENTER("pPtr", Ptr);
177
178         if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
179         {
180                 LEAVE_RET('n', NULL);
181         }
182
183         // Get descriptor range for packet
184         // TODO: Replace asserts with something a little more permissive        
185         Mutex_Acquire( &card->lRxPos );
186          int    first_td = card->RxPos;
187          int    nextp_td = first_td;
188         assert( card->RxQueue[first_td].Flags & RXDESC_FLG_STP );
189         while( !(card->RxQueue[nextp_td].Flags & RXDESC_FLG_ENP) )
190         {
191                 tRxDesc_3 *rd = &card->RxQueue[nextp_td];
192                 assert( !(rd->Flags & RXDESC_FLG_OWN) );
193                 // TODO: Check error bits properly
194                 if( rd->Flags & 0x7C000000 ) {
195                         Log_Notice("PCnet3", "Error bits set: 0x%x", (rd->Flags>>24) & 0x7C);
196                 }
197                 nextp_td = (nextp_td+1) % RLEN;
198                 assert(nextp_td != first_td);
199         }
200         nextp_td = (nextp_td+1) % RLEN;
201         card->RxPos = nextp_td;
202         Mutex_Release( &card->lRxPos );
203         
204          int    nDesc = (nextp_td - first_td + RLEN) % RLEN;
205
206         // Create buffer structure      
207         // TODO: Could be more efficient by checking for buffers in the same page / fully contig allocations
208         // - Meh
209         tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(nDesc);
210         for( int idx = first_td; idx != nextp_td; idx = (idx+1) % RLEN )
211         {
212                 tRxDesc_3 *rd = &card->RxQueue[idx];
213                 void    *ptr = card->RxBuffers[idx/RXBUF_PER_PAGE] + (idx%RXBUF_PER_PAGE)*RXBUFLEN;
214                 IPStack_Buffer_AppendSubBuffer(ret, (rd->Count & 0xFFF), 0, ptr, PCnet3_ReleaseRxD, rd);
215         }
216
217         LEAVE('p', ret);
218         return ret;
219 }
220
221 int PCnet3_int_FillTD(tTxDesc_3 *td, Uint32 BufAddr, Uint32 Len, int bBounced)
222 {
223         td->Flags0 = 0;
224         td->Flags1 = 0xF000 | (4096 - (Len & 0xFFF));
225         td->Buffer = BufAddr;
226         td->_avail = bBounced;
227         return 0;
228 }
229
230 int PCnet3_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
231 {
232         tCard   *card = Ptr;
233         
234         if( IPStack_Buffer_GetLength(Buffer) > 1500 ) {
235                 // MTU exceeded
236                 return EINVAL;
237         }
238         
239         ENTER("pPtr pBuffer", Ptr, Buffer);
240         // Need a sequence of `n` transmit descriptors
241         // - Can assume that descriptors are consumed FIFO from the current descriptor point
242          int    idx = 0;
243          int    nDesc = 0;
244         const void *sbuf_ptr;
245         size_t  sbuf_len;
246         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &sbuf_len, &sbuf_ptr)) != -1 )
247         {
248                 nDesc ++;
249                 #if PHYS_BITS > 32
250                 if( MM_GetPhysAddr(sbuf_ptr) > (1ULL<<32) )
251                         ;       // will be bounce-buffered
252                 else
253                 #endif
254                 if( MM_GetPhysAddr(sbuf_ptr)+sbuf_len-1 != MM_GetPhysAddr(sbuf_ptr+sbuf_len-1) )
255                 {
256                         // Split
257                         nDesc ++;
258                 }
259         }
260
261         // - Obtain enough descriptors
262         int rv = Semaphore_Wait(&card->TxDescSem, nDesc);
263         if( rv != nDesc ) {
264                 Log_Notice("PCnet3", "Semaphore wait interrupted, restoring %i descriptors");
265                 Semaphore_Signal(&card->TxDescSem, rv);
266                 LEAVE_RET('i', EINTR);
267         }
268         Mutex_Acquire(&card->lTxPos);
269         int first_desc = card->FirstFreeTx;
270         card->FirstFreeTx = (card->FirstFreeTx + nDesc) % TLEN;
271         Mutex_Release(&card->lTxPos);
272         
273         // - Set up descriptors
274          int    td_idx = first_desc;
275         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &sbuf_len, &sbuf_ptr)) != -1 )
276         {
277                 tTxDesc_3 *td = &card->TxQueue[td_idx];
278                 assert( !(td->Flags1 & TXDESC_FLG1_OWN) );
279                 td_idx = (td_idx + 1) % TLEN;
280                 
281                 tPAddr  start_phys = MM_GetPhysAddr(sbuf_ptr);
282                 size_t  page1_maxsize = PAGE_SIZE - (start_phys % PAGE_SIZE);
283                 tPAddr  end_phys = MM_GetPhysAddr(sbuf_ptr + sbuf_len-1);
284
285                 #if PHYS_BITS > 32
286                 if( start_phys > (1ULL<<32) || end_phys > (1ULL<<32) )
287                 {
288                         // TODO: Have a global set of bounce buffers
289                         tPAddr bounce_phys;
290                         void *bounce_virt = MM_AllocDMA(1, 32, &bounce_phys);
291                         memcpy(bounce_virt, sbuf_ptr, sbuf_len);
292                         // Copy to bounce buffer
293                         PCnet3_int_FillTD(td, bounce_phys, sbuf_len, 1);
294                         LOG("%i: Bounce buffer %P+%i (orig %P,%P) - %p",
295                                 idx, bounce_phys, sbuf_len, start_phys, end_phys, td);
296                 }
297                 else
298                 #endif
299                 if( start_phys+sbuf_len-1 != end_phys )
300                 {
301                         // Split buffer into two descriptors
302                         tTxDesc_3 *td2 = &card->TxQueue[td_idx];
303                         assert( !(td2->Flags1 & TXDESC_FLG1_OWN) );
304                         td_idx = (td_idx + 1) % TLEN;
305                         
306                         PCnet3_int_FillTD(td, start_phys, page1_maxsize, 0);
307                         
308                         size_t  page2_size = sbuf_len - page1_maxsize;
309                         PCnet3_int_FillTD(td2, end_phys - (page2_size-1), page2_size, 0);
310                         // - Explicitly set OWN on td2 because it's never the first, and `td` gets set below
311                         td2->Flags1 |= TXDESC_FLG1_OWN;
312                         
313                         LOG("%i: Split (%P,%P)+%i - %p,%p",
314                                 idx, td->Buffer, td2->Buffer, sbuf_len, td, td2);
315                 }
316                 else
317                 {
318                         PCnet3_int_FillTD(td, start_phys, sbuf_len, 0);
319                         LOG("%i: Straight %P+%i - %p",
320                                 idx, td->Buffer, sbuf_len, td);
321                 }
322                 // On every descriptor except the first, set OWN
323                 // - OWN set later once all are filled
324                 if( td != &card->TxQueue[first_desc] )
325                         td->Flags1 |= TXDESC_FLG1_OWN;
326         }
327
328         // - Lock buffer before allowing the card to continue
329         IPStack_Buffer_LockBuffer(Buffer);
330         
331         // - Set STP/ENP
332         card->TxQueue[first_desc].Flags1 |= TXDESC_FLG1_STP;
333         card->TxQueue[(td_idx+TLEN-1)%TLEN].Flags1 |= TXDESC_FLG1_ENP|TXDESC_FLG1_ADDFCS;
334         // - Set OWN on the first descriptor
335         card->TxQueue[first_desc].Flags1 |= TXDESC_FLG1_OWN;
336         card->TxQueueBuffers[first_desc] = Buffer;
337
338         LOG("CSR0=0x%x", _ReadCSR(card, 0));
339         LOG("Transmit started, waiting for completion");
340         
341         // Block here until packet is sent
342         // TODO: Should be able to return, but just in case
343         IPStack_Buffer_LockBuffer(Buffer);
344         IPStack_Buffer_UnlockBuffer(Buffer);
345         
346         LEAVE('i', 0);
347         return 0;
348 }
349
350 int PCnet3_int_InitCard(tCard *Card)
351 {
352         // Allocate ring buffers
353         Card->TxQueue = (void*)MM_AllocDMA(1, 32, &Card->TxQueuePhys);
354         if( !Card->TxQueue ) {
355                 return MODULE_ERR_MALLOC;
356         }
357         memset(Card->TxQueue, 0, TLEN*sizeof(*Card->TxQueue));
358         #if TLEN + RLEN <= PAGE_SIZE / (4*4)
359         Card->RxQueue = (void*)MM_AllocDMA(1, 32, &Card->RxQueuePhys);
360         if( !Card->RxQueue ) {
361                 return MODULE_ERR_MALLOC;
362         }
363         #else
364         Card->RxQueue = Card->TxQueue + TLEN;
365         Card->RxQueuePhys = Card->RxQueuePhys + TLEN*sizeof(*Card->TxQueue);
366         #endif
367
368         // Allocate Rx buffers
369         for( int i = 0; i < NUM_RXBUF_PAGES; i ++ )
370         {
371                 tPAddr  physaddr;
372                 Card->RxBuffers[i] = (void*)MM_AllocDMA(1, 32, &physaddr);
373                 if( !Card->RxBuffers[i] ) {
374                         return MODULE_ERR_MALLOC;
375                 }
376                 for( int j = 0; j < RXBUF_PER_PAGE; j ++ )
377                 {
378                         Card->RxQueue[i*RXBUF_PER_PAGE+j].Buffer = physaddr;
379                         physaddr += RXBUFLEN;
380                 }
381         }
382         
383         // Initialise semaphores
384         Semaphore_Init(&Card->TxDescSem, TLEN, TLEN, "PCnet3", "Tx Descriptors");
385         Semaphore_Init(&Card->ReadSemaphore, 0, RLEN, "PCnet3", "Rx Descriptors");
386         
387         // Fill Init Block for this card
388         gpPCnet3_InitBlock->Mode = (TLEN_LOG2 << 28) | (RLEN_LOG2 << 20);
389         gpPCnet3_InitBlock->PhysAddr1 = 0;
390         memcpy(&gpPCnet3_InitBlock->PhysAddr0, Card->MacAddr, 6);
391         gpPCnet3_InitBlock->LAdrF0 = -1;        // TODO: Allow these to be set by the IPStack
392         gpPCnet3_InitBlock->LAdrF1 = -1;
393         gpPCnet3_InitBlock->RDRA = Card->RxQueuePhys;
394         gpPCnet3_InitBlock->TDRA = Card->TxQueuePhys;
395
396         // Reset card
397         inw(Card->IOBase + REG_RESET);
398         _WriteBCR(Card, BCR_SWSTYLE, (1<<8)|3); // Set SSIZE32
399         LOG("BCR_SWSTYLE reads as 0x%x", _ReadBCR(Card, BCR_SWSTYLE));
400         LOG("CSR4 reads as 0x%x", _ReadCSR(Card, 4));
401
402         // Initialise
403         tPAddr  paddr = MM_GetPhysAddr(gpPCnet3_InitBlock);
404         _WriteCSR(Card, CSR_IBA0, paddr & 0xFFFF);
405         _WriteCSR(Card, CSR_IBA1, paddr >> 16);
406         _WriteCSR(Card, CSR_STATUS, CSR_STATUS_INIT|CSR_STATUS_IENA|CSR_STATUS_STRT);
407
408         return 0;
409 }
410
411 void PCnet3_IRQHandler(int Num, void *Ptr)
412 {
413         tCard   *card = Ptr;
414         Uint16  status = _ReadCSR(card, CSR_STATUS);
415
416         LOG("status = 0x%02x", status);
417         status &= ~CSR_STATUS_INTR;     // Read-only bit
418         
419         // Rx Interrupt
420         // META - Check LAPPEN bit in CSR3
421         if( status & CSR_STATUS_RINT )
422         {
423                 // TODO: Avoid issues when two packets arrive in one interrupt time
424                 Semaphore_Signal(&card->ReadSemaphore, 1);
425         }
426         
427         // Tx Interrupt
428         if( status & CSR_STATUS_TINT )
429         {
430                  int    idx;
431                 for( idx = card->FirstUsedTxD; idx != card->FirstFreeTx; idx = (idx+1)%TLEN )
432                 {
433                         tTxDesc_3 *td = &card->TxQueue[idx];
434                         // Stop on the first chip-owned TxD
435                         LOG("idx=%i, Flags1=0x%08x", idx, td->Flags1);
436                         if( td->Flags1 & TXDESC_FLG1_OWN )
437                                 break;
438                         if( td->Flags1 & (1<<30) )
439                         {
440                                 LOG(" Flags0=0x%08x %s%s%s%s%s%s%i",
441                                         td->Flags0,
442                                         (td->Flags0 & (1<<31)) ? "BUFF " : "",
443                                         (td->Flags0 & (1<<30)) ? "UFLO " : "",
444                                         (td->Flags0 & (1<<29)) ? "EXDEF " : "",
445                                         (td->Flags0 & (1<<28)) ? "LCOL " : "",
446                                         (td->Flags0 & (1<<27)) ? "LCAR " : "",
447                                         (td->Flags0 & (1<<26)) ? "RTRY " : "",
448                                         td->Flags0 & 15
449                                         );
450                         }
451                         if( td->Flags1 & TXDESC_FLG1_STP )
452                                 IPStack_Buffer_UnlockBuffer( card->TxQueueBuffers[idx] );
453                         Semaphore_Signal(&card->TxDescSem, 1);
454                 }
455                 card->FirstUsedTxD = idx;
456         }
457
458         if( status & CSR_STATUS_IDON )
459         {
460                 Log_Debug("PCnet3", "Card %p initialisation done", card);
461                 LOG("CSR15 reads as 0x%x", _ReadCSR(card, 15));
462         }
463
464         // ERR set?
465         if( status & 0xBC00 )
466         {
467                 Log_Notice("PCnet3", "Error on %p: %s%s%s%s",
468                         card,
469                         (status & (1<<15)) ? "ERR " : "",
470                         (status & (1<<13)) ? "CERR " : "",
471                         (status & (1<<12)) ? "MISS " : "",
472                         (status & (1<<11)) ? "MERR " : ""
473                         );
474         }
475
476         _WriteCSR(card, CSR_STATUS, status);
477 }
478
479 void PCnet3_ReleaseRxD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
480 {
481         tRxDesc_3       *rd = Arg;
482         rd->Flags &= 0xFFFF;
483         rd->Flags |= RXDESC_FLG_OWN;
484 }
485
486 static Uint16 _ReadCSR(tCard *Card, Uint8 Reg)
487 {
488         outd(Card->IOBase + REG_RAP, Reg);
489         return ind(Card->IOBase + REG_RDP);
490 }
491 static void _WriteCSR(tCard *Card, Uint8 Reg, Uint16 Value)
492 {
493         outd(Card->IOBase + REG_RAP, Reg);
494         outd(Card->IOBase + REG_RDP, Value);
495 }
496 static Uint16 _ReadBCR(tCard *Card, Uint8 Reg)
497 {
498         outd(Card->IOBase + REG_RAP, Reg);
499         return ind(Card->IOBase + REG_BDP);
500 }
501 void _WriteBCR(tCard *Card, Uint8 Reg, Uint16 Value)
502 {
503         outd(Card->IOBase + REG_RAP, Reg);
504         outd(Card->IOBase + REG_BDP, Value);
505 }
506

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