Kernel - TODO: Kernel-mode shell
[tpg/acess2.git] / KernelLand / Modules / Network / E1000 / e1000.c
1 /*
2  * Acess2 E1000 Network Driver
3  * - By John Hodge (thePowersGang)
4  *
5  * e1000.c
6  * - Intel 8254x Network Card Driver (core)
7  */
8 #define DEBUG   0
9 #define VERSION VER2(0,1)
10 #include <acess.h>
11 #include "e1000.h"
12 #include <modules.h>
13 #include <drv_pci.h>
14 #include <IPStack/include/adapters_api.h>
15 #include <timers.h>     // Time_Delay
16
17 const struct sSupportedCard {
18         Uint16  Vendor, Device;
19 } caSupportedCards[] = {
20         {0x8086, 0x100E},       // 82540EM-A Desktop
21         {0x8086, 0x1010},       // 82546EB-A1 Copper Dual Port
22         {0x8086, 0x1012},       // 82546EB-A1 Fiber
23         {0x8086, 0x1019},       // 82547[EG]I Copper
24         {0x8086, 0x101A},       // 82547EI Mobile
25         {0x8086, 0x101D},       // 82546EB-A1 Copper Quad Port
26 };
27 const int ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]);
28
29 // === PROTOTYPES ===
30  int    E1000_Install(char **Arguments);
31  int    E1000_Cleanup(void);
32 tIPStackBuffer  *E1000_WaitForPacket(void *Ptr);
33  int    E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
34 void    E1000_IRQHandler(int Num, void *Ptr);
35  int    E1000_int_InitialiseCard(tCard *Card);
36 Uint16  E1000_int_ReadEEPROM(tCard *Card, Uint8 WordIdx);
37
38 // === GLOBALS ===
39 MODULE_DEFINE(0, VERSION, E1000, E1000_Install, E1000_Cleanup, NULL);
40 tIPStack_AdapterType    gE1000_AdapterType = {
41         .Name = "E1000",
42         .Type = ADAPTERTYPE_ETHERNET_1G,        // TODO: Differentiate differnet wire protos and speeds
43         .Flags = ADAPTERFLAG_OFFLOAD_MAC,       // TODO: IP/TCP/UDP checksum offloading
44         .SendPacket = E1000_SendPacket,
45         .WaitForPacket = E1000_WaitForPacket
46         };
47 tCard   *gaE1000_Cards;
48
49 // === CODE ===
50 int E1000_Install(char **Arguments)
51 {
52          int    card_count = 0;
53         for( int modelidx = 0; modelidx < ciNumSupportedCards; modelidx ++ )
54         {
55                 const struct sSupportedCard     *cardtype = &caSupportedCards[modelidx];
56                 card_count += PCI_CountDevices(cardtype->Vendor, cardtype->Device);
57         }
58         LOG("card_count = %i", card_count);
59         if( card_count == 0 ) {
60                 LOG("Zero cards located");
61                 return MODULE_ERR_NOTNEEDED;
62         }
63
64         // Allocate card array
65         gaE1000_Cards = calloc(sizeof(tCard), card_count);
66         if( !gaE1000_Cards ) {
67                 Log_Warning("E1000", "Allocation of %i card structures failed", card_count);
68                 return MODULE_ERR_MALLOC;
69         }       
70
71         // Initialise cards
72         int card_idx = 0;
73         for( int modelidx = 0; modelidx < ciNumSupportedCards; modelidx ++ )
74         {
75                 const struct sSupportedCard     *cardtype = &caSupportedCards[modelidx];
76                 for( int id = -1, i = 0; (id = PCI_GetDevice(cardtype->Vendor, cardtype->Device, i)) != -1; i ++ )
77                 {
78                         tCard   *card = &gaE1000_Cards[card_idx++];
79                         card->MMIOBasePhys = PCI_GetValidBAR(id, 0, PCI_BARTYPE_MEMNP);
80                         if( !card->MMIOBasePhys ) {
81                                 Log_Warning("E1000", "Dev %i: BAR0 should be non-prefetchable memory", id);
82                                 continue;
83                         }
84
85                         card->IRQ = PCI_GetIRQ(id);
86                         IRQ_AddHandler(card->IRQ, E1000_IRQHandler, card);
87                         PCI_SetCommand(id, PCI_CMD_MEMENABLE|PCI_CMD_BUSMASTER, 0);
88                 
89                         Log_Debug("E1000", "Card %i: %P IRQ %i", card_idx, card->MMIOBasePhys, card->IRQ);
90
91                         if( E1000_int_InitialiseCard(card) ) {
92                                 Log_Warning("E1000", "Initialisation of card #%i failed", card_idx);
93                                 return MODULE_ERR_MALLOC;
94                         }
95                         
96                         card->IPStackHandle = IPStack_Adapter_Add(&gE1000_AdapterType, card, card->MacAddr);
97                 }
98         }
99         return MODULE_ERR_OK;
100 }
101
102 int E1000_Cleanup(void)
103 {
104         return 0;
105 }
106
107 void E1000_int_ReleaseRXD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
108 {
109         tCard   **cardptr = Arg;
110         tCard   *Card = *cardptr;
111          int    rxd = (Arg - (void*)Card->RXBackHandles) / sizeof(void*);
112
113         LOG("RXD %p %i being released", Card, rxd);
114         ASSERT(rxd >= 0 && rxd < NUM_RX_DESC);
115
116         Card->RXDescs[rxd].Status = 0;
117         Mutex_Acquire(&Card->lRXDescs);
118         if( rxd == REG32(Card, REG_RDT) ) {
119                 while( rxd != Card->FirstUnseenRXD && !(Card->RXDescs[rxd].Status & RXD_STS_DD) ) {
120                         rxd ++;
121                         if( rxd == NUM_RX_DESC )
122                                 rxd = 0;
123                 }
124                 REG32(Card, REG_RDT) = rxd;
125                 LOG("Updated RDT=%i", rxd);
126         }
127         Mutex_Release(&Card->lRXDescs);
128 }
129
130 tIPStackBuffer *E1000_WaitForPacket(void *Ptr)
131 {
132         tCard   *Card = Ptr;
133         
134         if( Semaphore_Wait(&Card->AvailPackets, 1) != 1 )
135                 return NULL;
136         
137         ENTER("pPtr", Ptr);
138
139         Mutex_Acquire(&Card->lRXDescs);
140          int    first_rxd = Card->FirstUnseenRXD;
141          int    last_rxd = first_rxd;
142          int    nDesc = 1;
143         while( last_rxd != Card->LastUnseenRXD  ) {
144                 if( !(Card->RXDescs[last_rxd].Status & RXD_STS_DD) )
145                         break;  // Oops, should ahve found an EOP first
146                 if( Card->RXDescs[last_rxd].Status & RXD_STS_EOP )
147                         break;
148                 nDesc ++;
149                 last_rxd = (last_rxd + 1) % NUM_RX_DESC;
150         }
151         Card->FirstUnseenRXD = (last_rxd + 1) % NUM_RX_DESC;
152         Mutex_Release(&Card->lRXDescs);
153
154         LOG("nDesc = %i, first_rxd = %i", nDesc, first_rxd);
155         tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(nDesc);
156          int    rxd = first_rxd;
157         for( int i = 0; i < nDesc; i ++ )
158         {
159                 IPStack_Buffer_AppendSubBuffer(ret, 0, Card->RXDescs[rxd].Length, Card->RXBuffers[rxd],
160                         E1000_int_ReleaseRXD, &Card->RXBackHandles[rxd]);
161         }
162
163         LEAVE('p', ret);
164         return ret;
165 }
166
167 int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
168 {
169         tCard   *Card = Ptr;
170
171         ENTER("pPtr pBuffer", Ptr, Buffer);
172
173          int    nDesc = 0;
174         size_t  len;
175         const void      *ptr;
176         // Count sub-buffers (including splitting cross-page entries)
177          int    idx = -1;
178         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
179         {
180                 if( len > PAGE_SIZE ) {
181                         LOG("len=%i > PAGE_SIZE", len);
182                         LEAVE('i', EINVAL);
183                         return EINVAL;
184                 }
185                 if( MM_GetPhysAddr(ptr) + len-1 != MM_GetPhysAddr((char*)ptr + len-1) ) {
186                         LOG("Buffer %p+%i spans non-contig physical pages", ptr, len);
187                         nDesc ++;
188                 }
189                 nDesc ++;
190         }
191         
192         // Request set of TX descriptors
193         int rv = Semaphore_Wait(&Card->FreeTxDescs, nDesc);
194         if(rv != nDesc) {
195                 LEAVE('i', EINTR);
196                 return EINTR;
197         }
198         Mutex_Acquire(&Card->lTXDescs);
199          int    first_txd = Card->FirstFreeTXD;
200         Card->FirstFreeTXD = (first_txd + nDesc) % NUM_TX_DESC;
201          int    last_txd = (first_txd + nDesc-1) % NUM_TX_DESC;
202
203         LOG("first_txd = %i, last_txd = %i", first_txd, last_txd);
204
205         // Populate buffers
206         idx = -1;
207          int txd = first_txd;
208         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
209         {
210                 //Debug_HexDump("E100 SendPacket", ptr, len);
211                 if( MM_GetPhysAddr(ptr) + len-1 != MM_GetPhysAddr((char*)ptr + len-1) )
212                 {
213                         size_t  remlen = PAGE_SIZE - ((tVAddr)ptr & (PAGE_SIZE-1));
214                         // Split in two
215                         // - First Page
216                         Card->TXDescs[txd].Buffer = MM_GetPhysAddr(ptr);
217                         Card->TXDescs[txd].Length = remlen;
218                         Card->TXDescs[txd].CMD = TXD_CMD_RS;
219                         txd = (txd + 1) % NUM_TX_DESC;
220                         // - Second page
221                         Card->TXDescs[txd].Buffer = MM_GetPhysAddr((char*)ptr + remlen);
222                         Card->TXDescs[txd].Length = len - remlen;
223                         Card->TXDescs[txd].CMD = TXD_CMD_RS;
224                 }
225                 else
226                 {
227                         // Single
228                         volatile tTXDesc *txdp = &Card->TXDescs[txd];
229                         txdp->Buffer = MM_GetPhysAddr(ptr);
230                         txdp->Length = len;
231                         txdp->CMD = TXD_CMD_RS;
232                         LOG("%P: %llx %x %x", MM_GetPhysAddr((void*)txdp), txdp->Buffer, txdp->Length, txdp->CMD);
233                 }
234                 txd = (txd + 1) % NUM_TX_DESC;
235         }
236         Card->TXDescs[last_txd].CMD |= TXD_CMD_EOP|TXD_CMD_IDE|TXD_CMD_IFCS;
237         Card->TXSrcBuffers[last_txd] = Buffer;
238
239         __sync_synchronize();
240         #if DEBUG
241         {
242                 volatile tTXDesc *txdp = Card->TXDescs + last_txd;
243                 LOG("%p %P: %llx %x %x", txdp, MM_GetPhysAddr((void*)txdp), txdp->Buffer, txdp->Length, txdp->CMD);
244                 volatile tTXDesc *txdp_base = MM_MapTemp(MM_GetPhysAddr((void*)Card->TXDescs));
245                 txdp = txdp_base + last_txd;
246                 LOG("%p %P: %llx %x %x", txdp, MM_GetPhysAddr((void*)txdp), txdp->Buffer, txdp->Length, txdp->CMD);
247                 MM_FreeTemp( (void*)txdp_base);
248         }
249         #endif
250         // Trigger TX
251         IPStack_Buffer_LockBuffer(Buffer);
252         LOG("Triggering TX - Buffers[%i]=%p", last_txd, Buffer);
253         REG32(Card, REG_TDT) = Card->FirstFreeTXD;
254         Mutex_Release(&Card->lTXDescs);
255         LOG("Waiting for TX to complete");
256         
257         // Wait for completion (lock will block, then release straight away)
258         IPStack_Buffer_LockBuffer(Buffer);
259         IPStack_Buffer_UnlockBuffer(Buffer);
260
261         // TODO: Check status bits
262
263         LEAVE('i', 0);
264         return 0;
265 }
266
267 void E1000_IRQHandler(int Num, void *Ptr)
268 {
269         tCard   *Card = Ptr;
270         
271         Uint32  icr = REG32(Card, REG_ICR);
272         if( icr == 0 )
273                 return ;
274         LOG("icr = %x", icr);
275
276         // Transmit descriptor written
277         if( (icr & ICR_TXDW) || (icr & ICR_TXQE) )
278         {
279                  int    nReleased = 0;
280                  int    txd = Card->LastFreeTXD;
281                  int    nReleasedAtLastDD = 0;
282                  int    idxOfLastDD = txd;
283                 // Walk descriptors looking for the first non-complete descriptor
284                 LOG("TX %i:%i", Card->LastFreeTXD, Card->FirstFreeTXD);
285                 while( txd != Card->FirstFreeTXD )
286                 {
287                         nReleased ++;
288                         if(Card->TXDescs[txd].Status & TXD_STS_DD) {
289                                 nReleasedAtLastDD = nReleased;
290                                 idxOfLastDD = txd;
291                         }
292                         txd ++;
293                         if(txd == NUM_TX_DESC)
294                                 txd = 0;
295                 }
296                 if( nReleasedAtLastDD )
297                 {
298                         // Unlock buffers
299                         txd = Card->LastFreeTXD;
300                         LOG("TX unlocking range %i-%i", txd, idxOfLastDD);
301                         while( txd != (idxOfLastDD+1)%NUM_TX_DESC )
302                         {
303                                 if( Card->TXSrcBuffers[txd] ) {
304                                         LOG("- Unlocking %i:%p", txd, Card->TXSrcBuffers[txd]);
305                                         IPStack_Buffer_UnlockBuffer( Card->TXSrcBuffers[txd] );
306                                         Card->TXSrcBuffers[txd] = NULL;
307                                 }
308                                 txd ++;
309                                 if(txd == NUM_TX_DESC)
310                                         txd = 0;
311                         }
312                         // Update last free
313                         Card->LastFreeTXD = txd;
314                         Semaphore_Signal(&Card->FreeTxDescs, nReleasedAtLastDD);
315                         LOG("nReleased = %i", nReleasedAtLastDD);
316                 }
317                 else
318                 {
319                         LOG("No completed TXDs");
320                 }
321         }       
322
323         if( icr & ICR_LSC )
324         {
325                 // Link status change
326                 LOG("LSC");
327                 // TODO: Detect link drop/raise and poke IPStack
328         }
329
330         if( icr & ICR_RXO )
331         {
332                 LOG("RX Overrun");
333         }
334         
335         // Pending packet (s)
336         if( icr & ICR_RXT0 )
337         {
338                  int    nPackets = 0;
339                 LOG("RX %i:%i", Card->LastUnseenRXD, Card->FirstUnseenRXD);
340                 while( (Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_DD) )
341                 {
342                         if( Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_EOP )
343                                 nPackets ++;
344                         Card->LastUnseenRXD ++;
345                         if( Card->LastUnseenRXD == NUM_RX_DESC )
346                                 Card->LastUnseenRXD = 0;
347                         
348                         if( Card->LastUnseenRXD == Card->FirstUnseenRXD )
349                                 break;
350                 }
351                 Semaphore_Signal(&Card->AvailPackets, nPackets);
352                 LOG("nPackets = %i", nPackets);
353         }
354         
355         // Transmit Descriptor Low Threshold hit
356         if( icr & ICR_TXD_LOW )
357         {
358                 
359         }
360
361         // Receive Descriptor Minimum Threshold Reached
362         // - We're reading too slow
363         if( icr & ICR_RXDMT0 )
364         {
365                 LOG("RX descs running out");
366         }
367         
368         icr &= ~(ICR_RXT0|ICR_LSC|ICR_TXQE|ICR_TXDW|ICR_TXD_LOW|ICR_RXDMT0);
369         if( icr )
370                 Log_Warning("E1000", "Unhandled ICR bits 0x%x", icr);
371 }
372
373 // TODO: Move this function into Kernel/drvutil.c
374 /**
375  * \brief Allocate a set of buffers in hardware mapped space
376  * 
377  * Allocates \a NumBufs buffers using shared pages (if \a BufSize is less than a page) or
378  * as a set of contiugious allocations.
379  */
380 int DrvUtil_AllocBuffers(void **Buffers, int NumBufs, int PhysBits, size_t BufSize)
381 {
382         if( BufSize >= PAGE_SIZE )
383         {
384                 const int       pages_per_buf = BufSize / PAGE_SIZE;
385                 ASSERT(pages_per_buf * PAGE_SIZE == BufSize);
386                 for( int i = 0; i < NumBufs; i ++ ) {
387                         Buffers[i] = (void*)MM_AllocDMA(pages_per_buf, PhysBits, NULL);
388                         if( !Buffers[i] )       return 1;
389                 }
390         }
391         else
392         {
393                 size_t  ofs = 0;
394                 const int       bufs_per_page = PAGE_SIZE / BufSize;
395                 ASSERT(bufs_per_page * BufSize == PAGE_SIZE);
396                 void    *page = NULL;
397                 for( int i = 0; i < NumBufs; i ++ )
398                 {
399                         if( ofs == 0 ) {
400                                 page = (void*)MM_AllocDMA(1, PhysBits, NULL);
401                                 if( !page )     return 1;
402                         }
403                         Buffers[i] = (char*)page + ofs;
404                         ofs += BufSize;
405                         if( ofs >= PAGE_SIZE )
406                                 ofs = 0;
407                 }
408         }
409         return 0;
410 }
411
412 int E1000_int_InitialiseCard(tCard *Card)
413 {
414         ENTER("pCard", Card);
415         
416         // Map required structures
417         Card->MMIOBase = (void*)MM_MapHWPages( Card->MMIOBasePhys, 7 );
418         if( !Card->MMIOBase ) {
419                 Log_Error("E1000", "%p: Failed to map MMIO Space (7 pages)", Card);
420                 LEAVE('i', 1);
421                 return 1;
422         }
423
424         // --- Read MAC address from EEPROM ---
425         {
426                 Uint16  macword;
427                 macword = E1000_int_ReadEEPROM(Card, 0);
428                 Card->MacAddr[0] = macword & 0xFF;
429                 Card->MacAddr[1] = macword >> 8;
430                 macword = E1000_int_ReadEEPROM(Card, 1);
431                 Card->MacAddr[2] = macword & 0xFF;
432                 Card->MacAddr[3] = macword >> 8;
433                 macword = E1000_int_ReadEEPROM(Card, 2);
434                 Card->MacAddr[4] = macword & 0xFF;
435                 Card->MacAddr[5] = macword >> 8;
436         }
437         Log_Log("E1000", "%p: MAC Address %02x:%02x:%02x:%02x:%02x:%02x",
438                 Card,
439                 Card->MacAddr[0], Card->MacAddr[1],
440                 Card->MacAddr[2], Card->MacAddr[3],
441                 Card->MacAddr[4], Card->MacAddr[5]);
442         
443         // --- Prepare for RX ---
444         LOG("RX Preparation");
445         Card->RXDescs = (void*)MM_AllocDMA(1, 64, NULL);
446         if( !Card->RXDescs ) {
447                 LEAVE('i', 2);
448                 return 2;
449         }
450         if( DrvUtil_AllocBuffers(Card->RXBuffers, NUM_RX_DESC, 64, RX_DESC_BSIZE) ) {
451                 LEAVE('i', 3);
452                 return 3;
453         }
454         for( int i = 0; i < NUM_RX_DESC; i ++ )
455         {
456                 Card->RXDescs[i].Buffer = MM_GetPhysAddr(Card->RXBuffers[i]);
457                 Card->RXDescs[i].Status = 0;    // Clear RXD_STS_DD, gives it to the card
458                 Card->RXBackHandles[i] = Card;
459         }
460         
461         REG64(Card, REG_RDBAL) = MM_GetPhysAddr((void*)Card->RXDescs);
462         REG32(Card, REG_RDLEN) = NUM_RX_DESC * 16;
463         REG32(Card, REG_RDH) = 0;
464         REG32(Card, REG_RDT) = NUM_RX_DESC;
465         // Hardware size, Multicast promisc, Accept broadcast, Interrupt at 1/4 Rx descs free
466         REG32(Card, REG_RCTL) = RX_DESC_BSIZEHW | RCTL_MPE | RCTL_BAM | RCTL_RDMTS_1_4;
467         Card->FirstUnseenRXD = 0;
468         Card->LastUnseenRXD = 0;
469
470         // --- Prepare for TX ---
471         LOG("TX Preparation");
472         Card->TXDescs = (void*)MM_AllocDMA(1, 64, NULL);
473         if( !Card->RXDescs ) {
474                 LEAVE('i', 4);
475                 return 4;
476         }
477         LOG("Card->RXDescs = %p [%P]", Card->TXDescs, MM_GetPhysAddr((void*)Card->TXDescs));
478         for( int i = 0; i < NUM_TX_DESC; i ++ )
479         {
480                 Card->TXDescs[i].Buffer = 0;
481                 Card->TXDescs[i].CMD = 0;
482         }
483         REG64(Card, REG_TDBAL) = MM_GetPhysAddr((void*)Card->TXDescs);
484         REG32(Card, REG_TDLEN) = NUM_TX_DESC * 16;
485         REG32(Card, REG_TDH) = 0;
486         REG32(Card, REG_TDT) = 0;
487         // Enable, pad short packets
488         REG32(Card, REG_TCTL) = TCTL_EN | TCTL_PSP | (0x0F << TCTL_CT_ofs) | (0x40 << TCTL_COLD_ofs);
489         Card->FirstFreeTXD = 0;
490
491         // -- Prepare Semaphores
492         Semaphore_Init(&Card->FreeTxDescs, NUM_TX_DESC, NUM_TX_DESC, "E1000", "TXDescs");
493         Semaphore_Init(&Card->AvailPackets, 0, NUM_RX_DESC, "E1000", "RXDescs");
494
495         // --- Prepare for full operation ---
496         LOG("Starting card");
497         REG32(Card, REG_CTRL) = CTRL_SLU|CTRL_ASDE;     // Link up, auto speed detection
498         REG32(Card, REG_IMS) = 0x1F6DC; // Interrupt mask
499         (void)REG32(Card, REG_ICR);     // Discard pending interrupts
500         REG32(Card, REG_RCTL) |= RCTL_EN;
501         LEAVE('i', 0);
502         return 0;
503 }
504
505 Uint16 E1000_int_ReadEEPROM(tCard *Card, Uint8 WordIdx)
506 {
507         REG32(Card, REG_EERD) = ((Uint32)WordIdx << 8) | 1;
508         Uint32  tmp;
509         while( !((tmp = REG32(Card, REG_EERD)) & (1 << 4)) ) {
510                 // TODO: use something like Time_MicroDelay instead
511                 Time_Delay(1);
512         }
513         
514         return tmp >> 16;
515 }

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