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

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