32aa7d4554edc9b75673bd02692f5a41a99b19e8
[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)|50)
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 enum eRTL8139_Regs
16 {
17         // MAC Address
18         MAC0, MAC1, MAC2,
19         MAC3, MAC4, MAC5,
20         
21         // Multicast Registers
22         MAR0 = 0x08, MAR1, MAR2, MAR3,
23         MAR4, MAR5, MAR6, MAR7,
24         
25         // Transmit status of descriptors 0 - 3
26         TSD0 = 0x10,    TSD1 = 0x14,
27         TSD2 = 0x18,    TSD3 = 0x1C,
28         // Transmit start addresses
29         TSAD0 = 0x20,   TSAD1 = 0x24,
30         TSAD2 = 0x28,   TSAD3 = 0x2C,
31         
32         RBSTART = 0x30, //!< Recieve Buffer Start (DWord)
33         // Early Recieve Byte Count
34         ERBCR = 0x34,   // 16-bits
35         // Early RX Status Register
36         ERSR = 0x36,
37         
38         // ??, ??, ??, RST, RE, TE, ??, ??
39         CMD     = 0x37,
40         
41         CAPR    = 0x38, // Current address of packet read
42         CBA     = 0x3A, // Current Buffer Address - Total byte count in RX buffer
43         
44         IMR     = 0x3C, // Interrupt mask register
45         ISR     = 0x3E, // Interrupt status register
46         
47         TCR     = 0x40, // Transmit Configuration Register
48         RCR     = 0x44, // Recieve Configuration Register
49         TCTR    = 0x48, // 32-bit timer (count)
50         MPC     = 0x4C, // Missed packet count (due to RX overflow)
51         
52         CR_9346 = 0x50,
53         CONFIG0 = 0x51,
54         CONFIG1 = 0x52,
55         // 0x53 resvd
56         TIMERINT = 0x54,        // Fires a timeout when TCTR equals this value
57         
58 };
59
60 #define FLAG_ISR_TOK    0x04
61 #define FLAG_ISR_ROK    0x01
62
63 // === TYPES ===
64 typedef struct sCard
65 {
66         Uint16  IOBase;
67         Uint8   IRQ;
68         
69          int    NumWaitingPackets;
70         
71         char    *ReceiveBuffer;
72         tPAddr  PhysReceiveBuffer;
73          int    ReceiveBufferLength;
74          int    SeenOfs;        //!< End of the most recently seen packet (by IRQ)
75         tMutex  ReadMutex;
76         tSemaphore      ReadSemaphore;
77         
78         char    *TransmitBuffers[4];
79         tPAddr  PhysTransmitBuffers[4];
80         BOOL    TransmitInUse;  // Flags for each transmit descriptor
81         
82         char    Name[2];
83         tVFS_Node       Node;
84         Uint8   MacAddr[6];
85 }       tCard;
86
87 // === PROTOTYPES ===
88  int    RTL8139_Install(char **Options);
89 char    *RTL8139_ReadDir(tVFS_Node *Node, int Pos);
90 tVFS_Node       *RTL8139_FindDir(tVFS_Node *Node, const char *Filename);
91  int    RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
92 Uint64  RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
93 Uint64  RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
94  int    RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Arg);
95 void    RTL8139_IRQHandler(int Num);
96
97 // === GLOBALS ===
98 MODULE_DEFINE(0, VERSION, RTL8139, RTL8139_Install, NULL, NULL);
99 tDevFS_Driver   gRTL8139_DriverInfo = {
100         NULL, "RTL8139",
101         {
102         .NumACLs = 1,
103         .ACLs = &gVFS_ACL_EveryoneRX,
104         .Flags = VFS_FFLAG_DIRECTORY,
105         .ReadDir = RTL8139_ReadDir,
106         .FindDir = RTL8139_FindDir,
107         .IOCtl = RTL8139_RootIOCtl
108         }
109 };
110  int    giRTL8139_CardCount;
111 tCard   *gaRTL8139_Cards;
112
113 // === CODE ===
114 /**
115  * \brief Installs the RTL8139 Driver
116  */
117 int RTL8139_Install(char **Options)
118 {
119          int    id = -1;
120          int    i = 0;
121         Uint16  base;
122         tCard   *card;
123         
124         giRTL8139_CardCount = PCI_CountDevices( 0x10EC, 0x8139, 0 );
125         
126         gaRTL8139_Cards = calloc( giRTL8139_CardCount, sizeof(tCard) );
127         
128         
129         while( (id = PCI_GetDevice(0x10EC, 0x8139, 0, id)) != -1 )
130         {
131                 base = PCI_AssignPort( id, 0, 0x100 );
132                 card = &gaRTL8139_Cards[i];
133                 card->IOBase = base;
134                 card->IRQ = PCI_GetIRQ( id );
135                 
136                 // Install IRQ Handler
137                 IRQ_AddHandler(card->IRQ, RTL8139_IRQHandler);
138                 
139                 // Power on
140                 outb( base + CONFIG1, 0x00 );
141
142                 // Reset (0x10 to CMD)
143                 outb( base + CMD, 0x10 );       
144                 while( inb(base + CMD) & 0x10 ) ;
145                 
146                 // Set up recieve buffer
147                 // - Allocate 3 pages below 4GiB for the recieve buffer (Allows 8k+16+1500)
148                 card->ReceiveBuffer = (void*)MM_AllocDMA( 3, 32, &card->PhysReceiveBuffer );
149                 outd(base + RBSTART, (Uint32)card->PhysReceiveBuffer);
150                 // Set IMR to Transmit OK and Receive OK
151                 outw(base + IMR, 0x5);
152                 
153                 // Set up transmit buffers
154                 // - 2 non-contiguous pages (each page can fit 2 1500 byte packets)
155                 card->TransmitBuffers[0] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[0] );
156                 card->TransmitBuffers[1] = card->TransmitBuffers[0] + 0x800;
157                 card->PhysTransmitBuffers[1] = card->PhysTransmitBuffers[0] + 0x800;
158                 
159                 card->TransmitBuffers[2] = (void*)MM_AllocDMA( 1, 32, &card->PhysTransmitBuffers[1] );
160                 card->TransmitBuffers[3] = card->TransmitBuffers[2] + 0x800;
161                 card->PhysTransmitBuffers[3] = card->PhysTransmitBuffers[2] + 0x800;
162                 
163                 outd(base + TSAD0, card->PhysTransmitBuffers[0]);
164                 outd(base + TSAD1, card->PhysTransmitBuffers[1]);
165                 outd(base + TSAD2, card->PhysTransmitBuffers[2]);
166                 outd(base + TSAD3, card->PhysTransmitBuffers[3]);
167                 
168                 // Set recieve buffer size and recieve mask
169                 // - Bit 7 being unset tells the card to overflow the recieve buffer if needed
170                 //   (i.e. when the packet starts at the end of the bufffer, it overflows up
171                 //    to 1500 bytes)
172                 outd(base + RCR, 0x0F);
173         
174                 // Recive Enable and Transmit Enable    
175                 outb(base + CMD, 0x0C);
176                 
177                 // Get the card's MAC address
178                 card->MacAddr[0] = inb(base+MAC0);
179                 card->MacAddr[1] = inb(base+MAC1);
180                 card->MacAddr[2] = inb(base+MAC2);
181                 card->MacAddr[3] = inb(base+MAC3);
182                 card->MacAddr[4] = inb(base+MAC4);
183                 card->MacAddr[5] = inb(base+MAC5);
184                 
185                 // Set VFS Node
186                 card->Name[0] = '0'+i;
187                 card->Name[1] = '\0';
188                 card->Node.ImplPtr = card;
189                 card->Node.NumACLs = 0;
190                 card->Node.CTime = now();
191                 card->Node.Write = RTL8139_Write;
192                 card->Node.Read = RTL8139_Read;
193                 card->Node.IOCtl = RTL8139_IOCtl;
194                 
195                 Log_Log("RTL8139", "Card %i 0x%04x %02x:%02x:%02x:%02x:%02x:%02x",
196                         i, base,
197                         card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
198                         card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
199                         );
200                 
201                 i ++;
202         }
203         return MODULE_ERR_OK;
204 }
205
206 // --- Root Functions ---
207 char *RTL8139_ReadDir(tVFS_Node *Node, int Pos)
208 {
209         if( Pos < 0 || Pos >= giRTL8139_CardCount )     return NULL;
210         
211         return strdup( gaRTL8139_Cards[Pos].Name );
212 }
213
214 tVFS_Node *RTL8139_FindDir(tVFS_Node *Node, const char *Filename)
215 {
216         //TODO: It might be an idea to supprt >10 cards
217         if(Filename[0] == '\0' || Filename[0] != '\0')  return NULL;
218         if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
219         return &gaRTL8139_Cards[ Filename[0]-'0' ].Node;
220 }
221
222 const char *csaRTL8139_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
223 int RTL8139_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
224 {
225         switch(ID)
226         {
227         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_RootIOCtls);
228         }
229         return 0;
230 }
231
232 // --- File Functions ---
233 Uint64 RTL8139_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
234 {
235         tCard   *card = Node->ImplPtr;
236          int    read_ofs, pkt_length;
237
238 retry:
239         Semaphore_Wait( &card->ReadSemaphore, 1 );
240         
241         Mutex_Acquire( &card->ReadMutex );
242         
243         read_ofs = ind( card->IOBase + CAPR ) - card->PhysReceiveBuffer;
244         
245         // Check for errors
246         if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
247                 Mutex_Release( &card->ReadMutex );
248                 goto retry;     // I feel evil
249         }
250         
251         pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
252         
253         // Get packet
254         if( Length > pkt_length )       Length = pkt_length;
255         memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
256         
257         // Update read offset
258         read_ofs += pkt_length + 4;
259         read_ofs = (read_ofs + 3) & ~3; // Align
260         if(read_ofs > card->ReceiveBufferLength)        read_ofs = 0;
261         outd(card->IOBase + CAPR, read_ofs + card->PhysReceiveBuffer);
262         
263         Mutex_Release( &card->ReadMutex );
264         
265         return Length;
266 }
267
268 Uint64 RTL8139_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
269 {
270          int    td;
271         Uint32  status;
272         tCard   *card = Node->ImplPtr;
273         
274         if( Length > 1500 )     return 0;       // MTU exceeded
275         
276         // TODO: Implement a semaphore for avaliable tranmit buffers
277         
278         // Find an avaliable descriptor
279         do {
280                 for( td = 0; td < 4; td ++ ) {
281                         if( !(card->TransmitInUse & (1 << td)) )
282                                 break;
283                 }
284         } while(td == 4 && (Threads_Yield(),1));
285         
286         // Transmit using descriptor `td`
287         card->TransmitInUse |= (1 << td);
288         // Copy to buffer
289         memcpy(card->TransmitBuffers[td], Buffer, Length);
290         // Start
291         status = 0;
292         status |= Length & 0x1FFF;      // 0-12: Length
293         status |= 0 << 13;      // 13: OWN bit
294         status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
295         outd(card->IOBase + TSD0 + td, status);
296         
297         return 0;
298 }
299
300 const char *csaRTL8139_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
301 int RTL8139_IOCtl(tVFS_Node *Node, int ID, void *Data)
302 {
303         switch(ID)
304         {
305         BASE_IOCTLS(DRV_TYPE_NETWORK, "RTL8139", VERSION, csaRTL8139_NodeIOCtls);
306         }
307         return 0;
308 }
309
310 void RTL8139_IRQHandler(int Num)
311 {
312          int    i, j;
313         tCard   *card;
314         Uint8   status;
315         for( i = 0; i < giRTL8139_CardCount; i ++ )
316         {
317                 card = &gaRTL8139_Cards[i];
318                 if( Num != card->IRQ )  break;
319                 
320                 status = inb(card->IOBase + ISR);
321                 
322                 // Transmit OK, a transmit descriptor is now free
323                 if( status & FLAG_ISR_TOK )
324                 {
325                         outb(card->IOBase + ISR, FLAG_ISR_TOK);
326                         for( j = 0; j < 4; j ++ )
327                         {
328                                 if( ind(card->IOBase + TSD0 + j) & 0x8000 ) {   // TSD TOK
329                                         card->TransmitInUse &= ~(1 << j);
330                                         // TODO: Update semaphore once implemented
331                                 }
332                         }
333                 }
334                 
335                 // Recieve OK, inform read
336                 if( status & FLAG_ISR_ROK )
337                 {
338                          int    read_ofs, end_ofs;
339                          int    packet_count = 0;
340                         
341                         // Scan recieve buffer for packets
342                         end_ofs = ind(card->IOBase + CBA) - card->PhysReceiveBuffer;
343                         read_ofs = card->SeenOfs;
344                         if( read_ofs > end_ofs )
345                         {
346                                 while( read_ofs < card->ReceiveBufferLength )
347                                 {
348                                         packet_count ++;
349                                         read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+1] + 2;
350                                 }
351                                 read_ofs = 0;
352                         }
353                         while( read_ofs < end_ofs )
354                         {
355                                 packet_count ++;
356                                 read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+1] + 2;
357                         }
358                         card->SeenOfs = read_ofs;
359                         
360                         Semaphore_Signal( &card->ReadSemaphore, packet_count );
361                         if( packet_count )
362                                 VFS_MarkAvaliable( &card->Node, 1 );
363                         
364                         outb(card->IOBase + ISR, FLAG_ISR_ROK);
365                 }
366         }
367 }

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