Networking - Bugfixing in IPStack/RTL8139 driver
[tpg/acess2.git] / 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 <tpl_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_TOK    0x04
64 #define FLAG_ISR_ROK    0x01
65
66 // === TYPES ===
67 typedef struct sCard
68 {
69         Uint16  IOBase;
70         Uint8   IRQ;
71         
72          int    NumWaitingPackets;
73         
74         char    *ReceiveBuffer;
75         tPAddr  PhysReceiveBuffer;
76          int    ReceiveBufferLength;
77          int    SeenOfs;        //!< End of the most recently seen packet (by IRQ)
78         tMutex  ReadMutex;
79         tSemaphore      ReadSemaphore;
80         
81         char    *TransmitBuffers[4];
82         tPAddr  PhysTransmitBuffers[4];
83         BOOL    TransmitInUse;  // Flags for each transmit descriptor
84          int    CurTXDecscriptor;
85         
86         char    Name[2];
87         tVFS_Node       Node;
88         Uint8   MacAddr[6];
89 }       tCard;
90
91 // === PROTOTYPES ===
92  int    RTL8139_Install(char **Options);
93 char    *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
94 tVFS_Node       *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
95  int    RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
96 Uint64  RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
97 Uint64  RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
98  int    RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
99 void    RTL8139_IRQHandler(int Num);
100
101 // === GLOBALS ===
102 MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
103 tDevFS_Driver   gRTL8139_DriverInfo = {
104         NULL, "RTL8139",
105         {
106         .NumACLs = 1,
107         .ACLs = &gVFS_ACL_EveryoneRX,
108         .Flags = VFS_FFLAG_DIRECTORY,
109         .ReadDir = RTL8139_ReadDir,
110         .FindDir = RTL8139_FindDir,
111         .IOCtl = RTL8139_RootIOCtl
112         }
113 };
114  int    giRTL8139_CardCount;
115 tCard   *gaRTL8139_Cards;
116
117 // === CODE ===
118 /**
119  * \brief Installs the RTL8139 Driver
120  */
121 int RTL8139_Install(char **Options)
122 {
123          int    id = -1;
124          int    i = 0;
125         Uint16  base;
126         tCard   *card;
127         
128         giRTL8139_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID, 0);
129         Log_Debug("RTL8139", "%i cards", giRTL8139_CardCount);
130         
131         if( giRTL8139_CardCount == 0 )  return MODULE_ERR_NOTNEEDED;
132         
133         gaRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
134         
135         //while( (id = PCI_GetDevice(0x10EC, 0x8139, 0, id)) != -1 )
136         while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, 0, i)) != -1 )
137         {
138                 card = &gaRTL8139_Cards[i];
139                 base = PCI_AssignPort( id, 0, 0x100 );
140                 card->IOBase = base;
141                 card->IRQ = PCI_GetIRQ( id );
142                 
143                 // Install IRQ Handler
144                 IRQ_AddHandler(card->IRQ, RTL8139_IRQHandler);
145                 
146                 // Power on
147                 outb( base + CONFIG1, 0x00 );
148
149                 // Reset (0x10 to CMD)
150                 outb( base + CMD, 0x10 );       
151                 while( inb(base + CMD) & 0x10 ) ;
152                 
153                 // Set up recieve buffer
154                 // - Allocate 3 pages below 4GiB for the recieve buffer (Allows 8k+16+1500)
155                 card->ReceiveBuffer = (void*)MM_AllocDMA( 3, 32, &card->PhysReceiveBuffer );
156                 card->ReceiveBufferLength = 8*1024+16;
157                 outd(base + RBSTART, (Uint32)card->PhysReceiveBuffer);
158                 outd(base + CBA, 0);
159                 outd(base + CAPR, 0);
160                 // Set IMR to Transmit OK and Receive OK
161                 outw(base + IMR, 0x5);
162                 
163                 // Set up transmit buffers
164                 // - 2 non-contiguous pages (each page can fit 2 1500 byte packets)
165                 card->TransmitBuffers[0] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[0] );
166                 card->TransmitBuffers[1] = card->TransmitBuffers[0] + 0x800;
167                 card->PhysTransmitBuffers[1] = card->PhysTransmitBuffers[0] + 0x800;
168                 
169                 card->TransmitBuffers[2] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[2] );
170                 card->TransmitBuffers[3] = card->TransmitBuffers[2] + 0x800;
171                 card->PhysTransmitBuffers[3] = card->PhysTransmitBuffers[2] + 0x800;
172                 
173                 outd(base + TSAD0, card->PhysTransmitBuffers[0]);
174                 outd(base + TSAD1, card->PhysTransmitBuffers[1]);
175                 outd(base + TSAD2, card->PhysTransmitBuffers[2]);
176                 outd(base + TSAD3, card->PhysTransmitBuffers[3]);
177                 
178                 // Set recieve buffer size and recieve mask
179                 // - Bit 7 being unset tells the card to overflow the recieve buffer if needed
180                 //   (i.e. when the packet starts at the end of the bufffer, it overflows up
181                 //    to 1500 bytes)
182                 outd(base + RCR, 0x0F);
183         
184                 // Recive Enable and Transmit Enable    
185                 outb(base + CMD, 0x0C);
186                 
187                 // Get the card's MAC address
188                 card->MacAddr[0] = inb(base+MAC0);
189                 card->MacAddr[1] = inb(base+MAC1);
190                 card->MacAddr[2] = inb(base+MAC2);
191                 card->MacAddr[3] = inb(base+MAC3);
192                 card->MacAddr[4] = inb(base+MAC4);
193                 card->MacAddr[5] = inb(base+MAC5);
194                 
195                 // Set VFS Node
196                 card->Name[0] = '0'+i;
197                 card->Name[1] = '\0';
198                 card->Node.ImplPtr = card;
199                 card->Node.NumACLs = 0;
200                 card->Node.CTime = now();
201                 card->Node.Write = RTL8139_Write;
202                 card->Node.Read = RTL8139_Read;
203                 card->Node.IOCtl = RTL8139_IOCtl;
204                 
205                 Log_Log("RTL8139", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
206                         i, card->IOBase, card->IRQ,
207                         card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
208                         card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
209                         );
210                 
211                 i ++;
212         }
213         
214         gRTL8139_DriverInfo.RootNode.Size = giRTL8139_CardCount;
215         DevFS_AddDevice( &gRTL8139_DriverInfo );
216         
217         return MODULE_ERR_OK;
218 }
219
220 // --- Root Functions ---
221 char *RTL8139_ReadDir(tVFS_Node *Node, int Pos)
222 {
223         if( Pos < 0 || Pos >= giRTL8139_CardCount )     return NULL;
224         
225         return strdup( gaRTL8139_Cards[Pos].Name );
226 }
227
228 tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename)
229 {
230         //TODO: It might be an idea to supprt >10 cards
231         if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
232         if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
233         return &gaRTL8139_Cards[ Filename[0]-'0' ].Node;
234 }
235
236 const char *csaRTL8139_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
237 int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
238 {
239         ENTER("pNode iID pData", Node, ID, Data);
240         switch(ID)
241         {
242         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_RootIOCtls);
243         }
244         LEAVE('i', 0);
245         return 0;
246 }
247
248 // --- File Functions ---
249 Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
250 {
251         tCard   *card = Node->ImplPtr;
252         Uint16  read_ofs, pkt_length;
253          int    new_read_ofs;
254
255         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
256
257 retry:
258         Semaphore_Wait( &card->ReadSemaphore, 1 );
259         
260         Mutex_Acquire( &card->ReadMutex );
261         
262         read_ofs = (inw( card->IOBase + CAPR ) + 0x10) & 0xFFFF;
263         LOG("read_ofs = %i", read_ofs);
264         
265         pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
266         
267         // Calculate new read offset
268         new_read_ofs = read_ofs + pkt_length + 4;
269         new_read_ofs = (new_read_ofs + 3) & ~3; // Align
270         if(new_read_ofs > card->ReceiveBufferLength)    new_read_ofs = 0;
271         new_read_ofs -= 0x10;   // I dunno
272         
273         // Check for errors
274         if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
275                 // Update CAPR
276                 outd(card->IOBase + CAPR, new_read_ofs);
277                 Mutex_Release( &card->ReadMutex );
278                 goto retry;     // I feel evil
279         }
280         
281         // Get packet
282         if( Length > pkt_length )       Length = pkt_length;
283         memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
284         
285         // Update CAPR
286         outw(card->IOBase + CAPR, new_read_ofs);
287         
288         Mutex_Release( &card->ReadMutex );
289         
290         LEAVE('i', Length);
291         
292         return Length;
293 }
294
295 Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
296 {
297          int    td;
298         Uint32  status;
299         tCard   *card = Node->ImplPtr;
300         
301         if( Length > 1500 )     return 0;       // MTU exceeded
302         
303         ENTER("pNode XLength pBuffer", Node, Length, Buffer);
304         
305         // TODO: Implement a semaphore for avaliable transmit buffers
306         
307         td = card->CurTXDecscriptor;
308         
309         // Find an avaliable descriptor
310         while( card->TransmitInUse & (1 << td) )
311                 Threads_Yield();
312         
313         LOG("td = %i", td);
314         
315         // Transmit using descriptor `td`
316         card->TransmitInUse |= (1 << td);
317         outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
318         LOG("card->PhysTransmitBuffers[td] = 0x%llx", card->PhysTransmitBuffers[td]);
319         // Copy to buffer
320         memcpy(card->TransmitBuffers[td], Buffer, Length);
321         // Start
322         status = 0;
323         status |= Length & 0x1FFF;      // 0-12: Length
324         status |= 0 << 13;      // 13: OWN bit
325         status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
326         LOG("status = 0x%08x", status);
327         outd(card->IOBase + TSD0 + td*4, status);
328         
329         card->CurTXDecscriptor ++;
330         card->CurTXDecscriptor %= 4;
331         
332         LEAVE('i', (int)Length);
333         
334         return Length;
335 }
336
337 const char *csaRTL8139_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
338 int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Data)
339 {
340         tCard   *card = Node->ImplPtr;
341         ENTER("pNode iID pData", Node, ID, Data);
342         switch(ID)
343         {
344         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_NodeIOCtls);
345         case NET_IOCTL_GETMAC:
346                 if( !CheckMem(Data, 6) ) {
347                         LEAVE('i', -1);
348                         return -1;
349                 }
350                 memcpy( Data, card->MacAddr, 6 );
351                 LEAVE('i', 1);
352                 return 1;
353         }
354         LEAVE('i', 0);
355         return 0;
356 }
357
358 void RTL8139_IRQHandler(int Num)
359 {
360          int    i, j;
361         tCard   *card;
362         Uint16  status;
363         
364         for( i = 0; i < giRTL8139_CardCount; i ++ )
365         {
366                 card = &gaRTL8139_Cards[i];
367                 if( Num != card->IRQ )  break;
368                 
369                 status = inw(card->IOBase + ISR);
370                 LOG("status = 0x%02x", status);
371                 
372                 // Transmit OK, a transmit descriptor is now free
373                 if( status & FLAG_ISR_TOK )
374                 {
375                         for( j = 0; j < 4; j ++ )
376                         {
377                                 if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
378                                         card->TransmitInUse &= ~(1 << j);
379                                         // TODO: Update semaphore once implemented
380                                 }
381                         }
382                         outw(card->IOBase + ISR, FLAG_ISR_TOK);
383                 }
384                 
385                 // Recieve OK, inform read
386                 if( status & FLAG_ISR_ROK )
387                 {
388                          int    read_ofs, end_ofs;
389                          int    packet_count = 0;
390                         
391                         // Scan recieve buffer for packets
392                         end_ofs = inw(card->IOBase + CBA);
393                         read_ofs = card->SeenOfs;
394                         LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
395                         if( read_ofs > end_ofs )
396                         {
397                                 while( read_ofs < card->ReceiveBufferLength )
398                                 {
399                                         packet_count ++;
400                                         LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
401                                                 packet_count, read_ofs,
402                                                 *(Uint16*)&card->ReceiveBuffer[read_ofs],
403                                                 *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
404                                                 );
405                                         read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
406                                         read_ofs = (read_ofs + 3) & ~3; // Align
407                                         
408                                 }
409                                 read_ofs = 0;
410                         }
411                         while( read_ofs < end_ofs )
412                         {
413                                 LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
414                                         packet_count, read_ofs,
415                                         *(Uint16*)&card->ReceiveBuffer[read_ofs],
416                                         *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
417                                         );
418                                 packet_count ++;
419                                 read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
420                                 read_ofs = (read_ofs + 3) & ~3; // Align
421                         }
422                         card->SeenOfs = read_ofs;
423                         
424                         LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
425                         
426                         Semaphore_Signal( &card->ReadSemaphore, packet_count );
427                         if( packet_count )
428                                 VFS_MarkAvaliable( &card->Node, 1 );
429                         
430                         outw(card->IOBase + ISR, FLAG_ISR_ROK);
431                 }
432         }
433 }

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