8492fe8f03593d5d09a61cc11483a1c6a66f106c
[tpg/acess2.git] / KernelLand / Modules / Network / RTL8139 / rtl8139.c
1 /*
2  * Acess2 RTL8139 Driver
3  * - By John Hodge (thePowersGang)
4  */
5 #define DEBUG   0
6 #define VERSION ((0<<8)|20)
7 #include <acess.h>
8 #include <modules.h>
9 #include <fs_devfs.h>
10 #include <drv_pci.h>
11 #include <api_drv_network.h>
12 #include <semaphore.h>
13
14 // === CONSTANTS ===
15 #define VENDOR_ID       0x10EC
16 #define DEVICE_ID       0x8139
17
18 enum eRTL8139_Regs
19 {
20         // MAC Address
21         MAC0, MAC1, MAC2,
22         MAC3, MAC4, MAC5,
23         
24         // Multicast Registers
25         MAR0 = 0x08, MAR1, MAR2, MAR3,
26         MAR4, MAR5, MAR6, MAR7,
27         
28         // Transmit status of descriptors 0 - 3
29         TSD0 = 0x10,    TSD1 = 0x14,
30         TSD2 = 0x18,    TSD3 = 0x1C,
31         // Transmit start addresses
32         TSAD0 = 0x20,   TSAD1 = 0x24,
33         TSAD2 = 0x28,   TSAD3 = 0x2C,
34         
35         RBSTART = 0x30, //!< Recieve Buffer Start (DWord)
36         // Early Recieve Byte Count
37         ERBCR = 0x34,   // 16-bits
38         // Early RX Status Register
39         ERSR = 0x36,
40         
41         // ??, ??, ??, RST, RE, TE, ??, ??
42         CMD     = 0x37,
43         
44         CAPR    = 0x38, // Current address of packet read
45         CBA     = 0x3A, // Current Buffer Address - Total byte count in RX buffer
46         
47         IMR     = 0x3C, // Interrupt mask register
48         ISR     = 0x3E, // Interrupt status register
49         
50         TCR     = 0x40, // Transmit Configuration Register
51         RCR     = 0x44, // Recieve Configuration Register
52         TCTR    = 0x48, // 32-bit timer (count)
53         MPC     = 0x4C, // Missed packet count (due to RX overflow)
54         
55         CR_9346 = 0x50,
56         CONFIG0 = 0x51,
57         CONFIG1 = 0x52,
58         // 0x53 resvd
59         TIMERINT = 0x54,        // Fires a timeout when TCTR equals this value
60         
61 };
62
63 #define FLAG_ISR_SERR   0x8000  // System error
64 #define FLAG_ISR_TIMEO  0x4000  // Timer timeout (See TIMERINT)
65 #define FLAG_ISR_LENCHG 0x2000  // Cable length changed
66 #define FLAG_ISR_FOVW   0x0040  // Rx FIFO Underflow
67 #define FLAG_ISR_PUN    0x0020  // Packet Underrung
68 #define FLAG_ISR_RXOVW  0x0010  // Rx Buffer Overflow
69 #define FLAG_ISR_TER    0x0008  // Tx Error
70 #define FLAG_ISR_TOK    0x0004  // Tx OK
71 #define FLAG_ISR_RER    0x0002  // Rx Error
72 #define FLAG_ISR_ROK    0x0001  // Rx OK
73
74 // === TYPES ===
75 typedef struct sCard
76 {
77         Uint16  IOBase;
78         Uint8   IRQ;
79         
80          int    NumWaitingPackets;
81         
82         char    *ReceiveBuffer;
83         tPAddr  PhysReceiveBuffer;
84          int    ReceiveBufferLength;
85          int    SeenOfs;        //!< End of the most recently seen packet (by IRQ)
86         tMutex  ReadMutex;
87         tSemaphore      ReadSemaphore;
88         
89         char    *TransmitBuffers[4];
90         tPAddr  PhysTransmitBuffers[4];
91         tMutex  TransmitInUse[4];
92         tMutex  CurTXProtector; //!< Protects \a .CurTXDescriptor
93          int    CurTXDescriptor;
94         
95         char    Name[2];
96         tVFS_Node       Node;
97         Uint8   MacAddr[6];
98 }       tCard;
99
100 // === PROTOTYPES ===
101  int    RTL8139_Install(char **Options);
102 char    *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
103 tVFS_Node       *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
104  int    RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
105 size_t  RTL8139_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
106 size_t  RTL8139_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
107  int    RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
108 void    RTL8139_IRQHandler(int Num, void *Ptr);
109
110 // === GLOBALS ===
111 MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
112 tVFS_NodeType   gRTL8139_RootNodeType = {
113         .ReadDir = RTL8139_ReadDir,
114         .FindDir = RTL8139_FindDir,
115         .IOCtl = RTL8139_IOCtl
116         };
117 tVFS_NodeType   gRTL8139_DevNodeType = {
118         .Write = RTL8139_Write,
119         .Read = RTL8139_Read,
120         .IOCtl = RTL8139_IOCtl  
121         };
122 tDevFS_Driver   gRTL8139_DriverInfo = {
123         NULL, "RTL8139",
124         {
125         .NumACLs = 1,
126         .ACLs = &gVFS_ACL_EveryoneRX,
127         .Flags = VFS_FFLAG_DIRECTORY,
128         .Type = &gRTL8139_RootNodeType
129         }
130 };
131  int    giRTL8139_CardCount;
132 tCard   *gaRTL8139_Cards;
133
134 // === CODE ===
135 /**
136  * \brief Installs the RTL8139 Driver
137  */
138 int RTL8139_Install(char **Options)
139 {
140          int    id = -1;
141          int    i = 0;
142         Uint16  base;
143         tCard   *card;
144         
145         giRTL8139_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
146         
147         if( giRTL8139_CardCount == 0 )  return MODULE_ERR_NOTNEEDED;
148
149         Log_Debug("RTL8139", "%i cards", giRTL8139_CardCount);  
150         gaRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
151         
152         for( i = 0 ; (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1; i ++ )
153         {
154                 card = &gaRTL8139_Cards[i];
155                 base = PCI_GetBAR( id, 0 );
156                 if( !(base & 1) ) {
157                         Log_Warning("RTL8139", "Driver does not support MMIO, skipping card (addr %x)",
158                                 base);
159                         card->IOBase = 0;
160                         card->IRQ = 0;
161                         continue ;
162                 }
163                 base &= ~1;
164                 card->IOBase = base;
165                 card->IRQ = PCI_GetIRQ( id );
166                 
167                 // Install IRQ Handler
168                 IRQ_AddHandler(card->IRQ, RTL8139_IRQHandler, card);
169                 
170                 // Power on
171                 outb( base + CONFIG1, 0x00 );
172
173                 // Reset (0x10 to CMD)
174                 outb( base + CMD, 0x10 );       
175                 while( inb(base + CMD) & 0x10 ) ;
176
177                 // Set IMR to all interrupts!
178                 outw(base + IMR, 0xE07F);
179                 
180                 // Set up recieve buffer
181                 // - Allocate 3 pages below 4GiB for the recieve buffer (Allows 8k+16+1500)
182                 card->ReceiveBuffer = (void*)MM_AllocDMA( 3, 32, &card->PhysReceiveBuffer );
183                 card->ReceiveBufferLength = 8*1024;
184                 outd(base + RBSTART, (Uint32)card->PhysReceiveBuffer);
185                 outd(base + CBA, 0);
186                 outd(base + CAPR, 0);
187                 
188                 // Set up transmit buffers
189                 // - 2 non-contiguous pages (each page can fit 2 1500 byte packets)
190                 card->TransmitBuffers[0] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[0] );
191                 card->TransmitBuffers[1] = card->TransmitBuffers[0] + 0x800;
192                 card->PhysTransmitBuffers[1] = card->PhysTransmitBuffers[0] + 0x800;
193                 
194                 card->TransmitBuffers[2] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[2] );
195                 card->TransmitBuffers[3] = card->TransmitBuffers[2] + 0x800;
196                 card->PhysTransmitBuffers[3] = card->PhysTransmitBuffers[2] + 0x800;
197                 
198                 outd(base + TSAD0, card->PhysTransmitBuffers[0]);
199                 outd(base + TSAD1, card->PhysTransmitBuffers[1]);
200                 outd(base + TSAD2, card->PhysTransmitBuffers[2]);
201                 outd(base + TSAD3, card->PhysTransmitBuffers[3]);
202                 
203                 // Set recieve buffer size and recieve mask
204                 // - Bit 7 being set tells the card to overflow the recieve buffer if needed
205                 //   (i.e. when the packet starts at the end of the bufffer, it overflows up
206                 //    to 1500 bytes)
207                 // Bits 10: 8 set the max DMA burst size (6=1024)
208                 // Bits 12:11 set the size (8k+16 -> 64k+16)
209                 // Bits 15:13 set the FIFO threshold (6 = 1024)
210                 outd(base + RCR, (6<<13)|(6<<8)|0x80|0x1F);     // All valid + runt packets
211         
212                 // Recive Enable and Transmit Enable    
213                 outb(base + CMD, 0x0C);
214                 
215                 // Get the card's MAC address
216                 card->MacAddr[0] = inb(base+MAC0);
217                 card->MacAddr[1] = inb(base+MAC1);
218                 card->MacAddr[2] = inb(base+MAC2);
219                 card->MacAddr[3] = inb(base+MAC3);
220                 card->MacAddr[4] = inb(base+MAC4);
221                 card->MacAddr[5] = inb(base+MAC5);
222                 
223                 // Set VFS Node
224                 card->Name[0] = '0'+i;
225                 card->Name[1] = '\0';
226                 card->Node.ImplPtr = card;
227                 card->Node.NumACLs = 0;
228                 card->Node.CTime = now();
229                 card->Node.Type = &gRTL8139_DevNodeType;
230                 
231                 Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
232                         i, card->IOBase, card->IRQ,
233                         card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
234                         card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
235                         );
236         }
237         
238         gRTL8139_DriverInfo.RootNode.Size = giRTL8139_CardCount;
239         DevFS_AddDevice( &gRTL8139_DriverInfo );
240         
241         return MODULE_ERR_OK;
242 }
243
244 // --- Root Functions ---
245 char *RTL8139_ReadDir(tVFS_Node *Node, int Pos)
246 {
247         if( Pos < 0 || Pos >= giRTL8139_CardCount )     return NULL;
248         
249         return strdup( gaRTL8139_Cards[Pos].Name );
250 }
251
252 tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename)
253 {
254         //TODO: It might be an idea to supprt >10 cards
255         if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
256         if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
257         return &gaRTL8139_Cards[ Filename[0]-'0' ].Node;
258 }
259
260 const char *csaRTL8139_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
261 int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
262 {
263         ENTER("pNode iID pData", Node, ID, Data);
264         switch(ID)
265         {
266         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_RootIOCtls);
267         }
268         LEAVE('i', 0);
269         return 0;
270 }
271
272 // --- File Functions ---
273 size_t RTL8139_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
274 {
275         tCard   *card = Node->ImplPtr;
276         Uint16  read_ofs, pkt_length;
277          int    new_read_ofs;
278
279         ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);
280
281 retry:
282         if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
283         {
284                 LEAVE_RET('i', 0);
285         }
286         
287         Mutex_Acquire( &card->ReadMutex );
288         
289         read_ofs = inw( card->IOBase + CAPR );
290         LOG("raw read_ofs = %i", read_ofs);
291         read_ofs = (read_ofs + 0x10) & 0xFFFF;
292         LOG("read_ofs = %i", read_ofs);
293         
294         pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
295         
296         // Calculate new read offset
297         new_read_ofs = read_ofs + pkt_length + 4;
298         new_read_ofs = (new_read_ofs + 3) & ~3; // Align
299         if(new_read_ofs > card->ReceiveBufferLength) {
300                 LOG("wrapping read_ofs");
301                 new_read_ofs -= card->ReceiveBufferLength;
302         }
303         new_read_ofs -= 0x10;   // I dunno
304         LOG("new_read_ofs = %i", new_read_ofs);
305         
306         // Check for errors
307         if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
308                 // Update CAPR
309                 outw(card->IOBase + CAPR, new_read_ofs);
310                 Mutex_Release( &card->ReadMutex );
311                 goto retry;     // I feel evil
312         }
313         
314         // Get packet
315         if( Length > pkt_length )       Length = pkt_length;
316         memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
317         
318         // Update CAPR
319         outw(card->IOBase + CAPR, new_read_ofs);
320         
321         Mutex_Release( &card->ReadMutex );
322         
323         LEAVE('i', Length);
324         
325         return Length;
326 }
327
328 size_t RTL8139_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
329 {
330          int    td;
331         Uint32  status;
332         tCard   *card = Node->ImplPtr;
333         
334         if( Length > 1500 )     return 0;       // MTU exceeded
335         
336         ENTER("pNode XLength pBuffer", Node, Length, Buffer);
337         
338         // TODO: Implement a semaphore for avaliable transmit buffers
339
340         // Find an avaliable descriptor
341         Mutex_Acquire(&card->CurTXProtector);
342         td = card->CurTXDescriptor;
343         card->CurTXDescriptor ++;
344         card->CurTXDescriptor %= 4;
345         Mutex_Release(&card->CurTXProtector);
346         // - Lock it
347         Mutex_Acquire( &card->TransmitInUse[td] );
348         
349         LOG("td = %i", td);
350         
351         // Transmit using descriptor `td`
352         LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
353         outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
354         LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
355         // Copy to buffer
356         memcpy(card->TransmitBuffers[td], Buffer, Length);
357         // Start
358         status = 0;
359         status |= Length & 0x1FFF;      // 0-12: Length
360         status |= 0 << 13;      // 13: OWN bit
361         status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
362         LOG("status = 0x%08x", status);
363         outd(card->IOBase + TSD0 + td*4, status);
364         
365         LEAVE('i', (int)Length);
366         
367         return Length;
368 }
369
370 const char *csaRTL8139_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
371 int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Data)
372 {
373         tCard   *card = Node->ImplPtr;
374         ENTER("pNode iID pData", Node, ID, Data);
375         switch(ID)
376         {
377         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_NodeIOCtls);
378         case NET_IOCTL_GETMAC:
379                 if( !CheckMem(Data, 6) ) {
380                         LEAVE('i', -1);
381                         return -1;
382                 }
383                 memcpy( Data, card->MacAddr, 6 );
384                 LEAVE('i', 1);
385                 return 1;
386         }
387         LEAVE('i', 0);
388         return 0;
389 }
390
391 void RTL8139_IRQHandler(int Num, void *Ptr)
392 {
393          int    j;
394         tCard   *card = Ptr;
395         Uint16  status;
396
397         LOG("Num = %i", Num);
398         
399         if( Num != card->IRQ )  return;
400                 
401         status = inw(card->IOBase + ISR);
402         LOG("status = 0x%02x", status);
403                 
404         // Transmit OK, a transmit descriptor is now free
405         if( status & FLAG_ISR_TOK )
406         {
407                 for( j = 0; j < 4; j ++ )
408                 {
409                         if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
410                                 Mutex_Release( &card->TransmitInUse[j] );
411                                 // TODO: Update semaphore once implemented
412                         }
413                 }
414                 outw(card->IOBase + ISR, FLAG_ISR_TOK);
415         }
416
417         // Transmit error, ... oops
418         if( status & FLAG_ISR_TER )
419         {
420                 Log_Error("RTK8139", "Tx Error, dunno what to do");
421                 outw(card->IOBase + ISR, FLAG_ISR_TER);
422         }
423         
424         // Recieve OK, inform read
425         if( status & FLAG_ISR_ROK )
426         {
427                  int    read_ofs, end_ofs;
428                  int    packet_count = 0;
429                  int    len;
430                 
431                 // Scan recieve buffer for packets
432                 end_ofs = inw(card->IOBase + CBA);
433                 read_ofs = card->SeenOfs;
434                 LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
435                 if( read_ofs > end_ofs )
436                 {
437                         while( read_ofs < card->ReceiveBufferLength )
438                         {
439                                 packet_count ++;
440                                 len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
441                                 LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
442                                         packet_count, read_ofs,
443                                         *(Uint16*)&card->ReceiveBuffer[read_ofs],
444                                         len
445                                         );
446                                 if(len > 2000) {
447                                         Log_Warning("RTL8139", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
448                                 }
449                                 read_ofs += len + 4;
450                                 read_ofs = (read_ofs + 3) & ~3; // Align
451                         }
452                         read_ofs -= card->ReceiveBufferLength;
453                         LOG("wrapped read_ofs");
454                 }
455                 while( read_ofs < end_ofs )
456                 {
457                         packet_count ++;
458 //                      Log_Debug("RTL8139", "RX %i at 0x%x", packet_count, read_ofs);
459                         LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
460                                 packet_count, read_ofs,
461                                 *(Uint16*)&card->ReceiveBuffer[read_ofs],
462                                 *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
463                                 );
464                         read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
465                         read_ofs = (read_ofs + 3) & ~3; // Align
466                 }
467                 if( read_ofs != end_ofs ) {
468                         Log_Warning("RTL8139", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
469                         read_ofs = end_ofs;
470                 }
471                 card->SeenOfs = read_ofs;
472                 
473                 LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
474                 
475                 if( packet_count )
476                 {
477                         if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
478                                 // Oops?
479                         }
480                         VFS_MarkAvaliable( &card->Node, 1 );
481                 }
482                 
483                 outw(card->IOBase + ISR, FLAG_ISR_ROK);
484         }
485         
486         // Recieve error, ... oops
487         if( status & FLAG_ISR_RER )
488         {
489                 Log_Error("RTL8139", "Rx Error, dunno what to do");
490                 outw(card->IOBase + ISR, FLAG_ISR_RER);
491         }
492
493         // Packet Underrun/Link Change
494         if( status & FLAG_ISR_PUN )
495         {
496                 // Set when CAPR is written but Rx is empty, OR when the link status changes
497                 Log_Notice("RTL8139", "ISR[PUN] set... hmmm");
498                 outw(card->IOBase + ISR, FLAG_ISR_PUN);
499         }
500
501         // Rx Overflow
502         if( status & FLAG_ISR_RXOVW )
503         {
504                 Log_Error("RTL8139", "Rx Overflow... oh fsck");
505                 outw(card->IOBase + ISR, FLAG_ISR_RXOVW);
506         }
507
508         // Rx FIFO Overflow
509         if( status & FLAG_ISR_FOVW )
510         {
511                 Log_Error("RTL8139", "Rx FIFO Overflow... huh?");
512                 outw(card->IOBase + ISR, FLAG_ISR_FOVW);
513         }
514 }

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