644d6940dd1546c6d07ee644f9d013b8730c6a39
[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   1
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                 return MODULE_ERR_MALLOC;
68         }       
69
70         // Initialise cards
71         int card_idx = 0;
72         for( int modelidx = 0; modelidx < ciNumSupportedCards; modelidx ++ )
73         {
74                 const struct sSupportedCard     *cardtype = &caSupportedCards[modelidx];
75                 for( int id = -1, i = 0; (id = PCI_GetDevice(cardtype->Vendor, cardtype->Device, i)) != -1; i ++ )
76                 {
77                         tCard   *card = &gaE1000_Cards[card_idx++];
78                         Uint32  mmiobase = PCI_GetBAR(id, 0);
79                         if( mmiobase & (1|8) ) {
80                                 Log_Warning("E1000", "Dev %i: BAR0 should be non-prefetchable memory", id);
81                                 continue;
82                         }
83                         const int addrsize = (mmiobase>>1) & 3;
84                         if( addrsize == 0 ) {
85                                 // Standard 32-bit
86                                 card->MMIOBasePhys = mmiobase & ~0xF;
87                         }
88                         else if( addrsize == 2 ) {
89                                 // 64-bit
90                                 card->MMIOBasePhys = (mmiobase & ~0xF) | ((Uint64)PCI_GetBAR(id, 1)<<32);
91                         }
92                         else {
93                                 Log_Warning("E1000", "Dev %i: Unknown memory address size %i", id, (mmiobase>>1)&3);
94                                 continue;
95                         }
96
97                         card->IRQ = PCI_GetIRQ(id);
98                         IRQ_AddHandler(card->IRQ, E1000_IRQHandler, card);
99
100                         Log_Debug("E1000", "Card %i: %P IRQ %i", card_idx, card->MMIOBasePhys, card->IRQ);
101
102                         if( E1000_int_InitialiseCard(card) ) {
103                                 return MODULE_ERR_MALLOC;
104                         }
105                         
106                         card->IPStackHandle = IPStack_Adapter_Add(&gE1000_AdapterType, card, card->MacAddr);
107                 }
108         }
109         return MODULE_ERR_OK;
110 }
111
112 int E1000_Cleanup(void)
113 {
114         return 0;
115 }
116
117 void E1000_int_ReleaseRXD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
118 {
119         tCard   **cardptr = Arg;
120         tCard   *Card = *cardptr;
121          int    rxd = (Arg - (void*)Card->RXDescs) / sizeof(tRXDesc);
122         
123         Card->RXDescs[rxd].Status = 0;
124         Mutex_Acquire(&Card->lRXDescs);
125         if( rxd == REG32(Card, REG_RDT) ) {
126                 while( rxd != Card->FirstUnseenRXD && !(Card->RXDescs[rxd].Status & RXD_STS_DD) ) {
127                         rxd ++;
128                         if( rxd == NUM_RX_DESC )
129                                 rxd = 0;
130                 }
131                 REG32(Card, REG_RDT) = rxd;
132                 LOG("Updated RDT=%i", rxd);
133         }
134         Mutex_Release(&Card->lRXDescs);
135 }
136
137 tIPStackBuffer *E1000_WaitForPacket(void *Ptr)
138 {
139         tCard   *Card = Ptr;
140         
141         if( Semaphore_Wait(&Card->AvailPackets, 1) != 1 )
142                 return NULL;
143         
144         ENTER("pPtr", Ptr);
145
146         Mutex_Acquire(&Card->lRXDescs);
147          int    first_rxd = Card->FirstUnseenRXD;
148          int    last_rxd = first_rxd;
149          int    nDesc = 1;
150         while( last_rxd != Card->LastUnseenRXD  ) {
151                 if( !(Card->RXDescs[last_rxd].Status & RXD_STS_DD) )
152                         break;  // Oops, should ahve found an EOP first
153                 if( Card->RXDescs[last_rxd].Status & RXD_STS_EOP )
154                         break;
155                 nDesc ++;
156                 last_rxd = (last_rxd + 1) % NUM_RX_DESC;
157         }
158         Card->FirstUnseenRXD = (last_rxd + 1) % NUM_RX_DESC;
159         Mutex_Release(&Card->lRXDescs);
160
161         LOG("nDesc = %i, first_rxd = %i", nDesc, first_rxd);
162         tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(nDesc);
163          int    rxd = first_rxd;
164         for( int i = 0; i < nDesc; i ++ )
165         {
166                 IPStack_Buffer_AppendSubBuffer(ret, 0, Card->RXDescs[rxd].Length, Card->RXBuffers[rxd],
167                         E1000_int_ReleaseRXD, &Card->RXBackHandles[rxd]);
168         }
169
170         LEAVE('p', ret);
171         return ret;
172 }
173
174 int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
175 {
176         tCard   *Card = Ptr;
177
178         ENTER("pPtr pBuffer", Ptr, Buffer);
179
180          int    nDesc = 0;
181         size_t  len;
182         const void      *ptr;
183         // Count sub-buffers (including splitting cross-page entries)
184          int    idx = -1;
185         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
186         {
187                 if( len > PAGE_SIZE ) {
188                         LOG("len=%i > PAGE_SIZE", len);
189                         LEAVE('i', EINVAL);
190                         return EINVAL;
191                 }
192                 if( MM_GetPhysAddr(ptr) + len-1 != MM_GetPhysAddr((char*)ptr + len-1) ) {
193                         LOG("Buffer %p+%i spans non-contig physical pages", ptr, len);
194                         nDesc ++;
195                 }
196                 nDesc ++;
197         }
198         
199         // Request set of TX descriptors
200         int rv = Semaphore_Wait(&Card->FreeTxDescs, nDesc);
201         if(rv != nDesc) {
202                 LEAVE('i', EINTR);
203                 return EINTR;
204         }
205         Mutex_Acquire(&Card->lTXDescs);
206          int    first_txd = Card->FirstFreeTXD;
207         Card->FirstFreeTXD = (first_txd + nDesc) % NUM_TX_DESC;
208          int    last_txd = (first_txd + nDesc-1) % NUM_TX_DESC;
209
210         LOG("first_txd = %i, last_txd = %i", first_txd, last_txd);
211
212         // Populate buffers
213         idx = -1;
214          int txd = first_txd;
215         while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
216         {
217                 if( MM_GetPhysAddr(ptr) + len-1 != MM_GetPhysAddr((char*)ptr + len-1) )
218                 {
219                         size_t  remlen = PAGE_SIZE - ((tVAddr)ptr & (PAGE_SIZE-1));
220                         // Split in two
221                         // - First Page
222                         Card->TXDescs[txd].Buffer = MM_GetPhysAddr(ptr);
223                         Card->TXDescs[txd].Length = remlen;
224                         Card->TXDescs[txd].CMD = TXD_CMD_RS;
225                         txd = (txd + 1) % NUM_TX_DESC;
226                         // - Second page
227                         Card->TXDescs[txd].Buffer = MM_GetPhysAddr((char*)ptr + remlen);
228                         Card->TXDescs[txd].Length = len - remlen;
229                         Card->TXDescs[txd].CMD = TXD_CMD_RS;
230                 }
231                 else
232                 {
233                         // Single
234                         Card->TXDescs[txd].Buffer = MM_GetPhysAddr(ptr);
235                         Card->TXDescs[txd].Length = len;
236                         Card->TXDescs[txd].CMD = TXD_CMD_RS;
237                 }
238                 txd = (txd + 1) % NUM_TX_DESC;
239         }
240         Card->TXDescs[last_txd].CMD |= TXD_CMD_EOP|TXD_CMD_IDE|TXD_CMD_IFCS;
241         Card->TXSrcBuffers[last_txd] = Buffer;
242
243         // Trigger TX
244         IPStack_Buffer_LockBuffer(Buffer);
245         REG32(Card, REG_TDT) = Card->FirstFreeTXD;
246         Mutex_Release(&Card->lTXDescs);
247         LOG("Waiting for TX");
248         
249         // Wait for completion (lock will block, then release straight away)
250         IPStack_Buffer_LockBuffer(Buffer);
251         IPStack_Buffer_UnlockBuffer(Buffer);
252
253         // TODO: Check status bits
254
255         LEAVE('i', 0);
256         return 0;
257 }
258
259 void E1000_IRQHandler(int Num, void *Ptr)
260 {
261         tCard   *Card = Ptr;
262         
263         Uint32  icr = REG32(Card, REG_ICR);
264         if( icr == 0 )
265                 return ;
266         LOG("icr = %x", icr);
267
268         // Transmit descriptor written
269         if( (icr & ICR_TXDW) || (icr & ICR_TXQE) )
270         {
271                  int    nReleased = 0;
272                 // Walk descriptors looking for the first non-complete descriptor
273                 LOG("TX %i:%i", Card->LastFreeTXD, Card->FirstFreeTXD);
274                 while( Card->LastFreeTXD != Card->FirstFreeTXD && (Card->TXDescs[Card->LastFreeTXD].Status & TXD_STS_DD) )
275                 {
276                         nReleased ++;
277                         if( Card->TXSrcBuffers[Card->LastFreeTXD] ) {
278                                 IPStack_Buffer_UnlockBuffer( Card->TXSrcBuffers[Card->LastFreeTXD] );
279                                 Card->TXSrcBuffers[Card->LastFreeTXD] = NULL;
280                         }
281                         Card->LastFreeTXD ++;
282                         if(Card->LastFreeTXD == NUM_TX_DESC)
283                                 Card->LastFreeTXD = 0;
284                 }
285                 Semaphore_Signal(&Card->FreeTxDescs, nReleased);
286                 LOG("nReleased = %i", nReleased);
287         }
288         
289         if( icr & ICR_LSC )
290         {
291                 // Link status change
292                 LOG("LSC");
293                 // TODO: Detect link drop/raise and poke IPStack
294         }
295         
296         // Pending packet (s)
297         if( icr & ICR_RXT0 )
298         {
299                  int    nPackets = 0;
300                 LOG("RX %i:%i", Card->LastUnseenRXD, Card->FirstUnseenRXD);
301                 while( (Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_DD) )
302                 {
303                         if( Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_EOP )
304                                 nPackets ++;
305                         Card->LastUnseenRXD ++;
306                         if( Card->LastUnseenRXD == NUM_RX_DESC )
307                                 Card->LastUnseenRXD = 0;
308                         
309                         if( Card->LastUnseenRXD == Card->FirstUnseenRXD )
310                                 break;
311                 }
312                 Semaphore_Signal(&Card->AvailPackets, nPackets);
313                 LOG("nPackets = %i", nPackets);
314         }
315         
316         icr &= ~(ICR_RXT0|ICR_LSC|ICR_TXQE|ICR_TXDW);
317         if( icr )
318                 Log_Warning("E1000", "Unhandled ICR bits 0x%x", icr);
319 }
320
321 // TODO: Move this function into Kernel/drvutil.c
322 /**
323  * \brief Allocate a set of buffers in hardware mapped space
324  * 
325  * Allocates \a NumBufs buffers using shared pages (if \a BufSize is less than a page) or
326  * as a set of contiugious allocations.
327  */
328 int DrvUtil_AllocBuffers(void **Buffers, int NumBufs, int PhysBits, size_t BufSize)
329 {
330         if( BufSize >= PAGE_SIZE )
331         {
332                 const int       pages_per_buf = BufSize / PAGE_SIZE;
333                 ASSERT(pages_per_buf * PAGE_SIZE == BufSize);
334                 for( int i = 0; i < NumBufs; i ++ ) {
335                         Buffers[i] = (void*)MM_AllocDMA(pages_per_buf, PhysBits, NULL);
336                         if( !Buffers[i] )       return 1;
337                 }
338         }
339         else
340         {
341                 size_t  ofs = 0;
342                 const int       bufs_per_page = PAGE_SIZE / BufSize;
343                 ASSERT(bufs_per_page * BufSize == PAGE_SIZE);
344                 void    *page;
345                 for( int i = 0; i < NumBufs; i ++ )
346                 {
347                         if( ofs == 0 ) {
348                                 page = (void*)MM_AllocDMA(1, PhysBits, NULL);
349                                 if( !page )     return 1;
350                         }
351                         Buffers[i] = (char*)page + ofs;
352                         ofs += BufSize;
353                         if( ofs >= PAGE_SIZE )
354                                 ofs = 0;
355                 }
356         }
357         return 0;
358 }
359
360 int E1000_int_InitialiseCard(tCard *Card)
361 {
362         ENTER("pCard", Card);
363         
364         // Map required structures
365         Card->MMIOBase = (void*)MM_MapHWPages( Card->MMIOBasePhys, 7 );
366         if( !Card->MMIOBase ) {
367                 Log_Error("E1000", "%p: Failed to map MMIO Space (7 pages)", Card);
368                 LEAVE('i', 1);
369                 return 1;
370         }
371
372         // --- Read MAC address from EEPROM ---
373         {
374                 Uint16  macword;
375                 macword = E1000_int_ReadEEPROM(Card, 0);
376                 Card->MacAddr[0] = macword & 0xFF;
377                 Card->MacAddr[1] = macword >> 8;
378                 macword = E1000_int_ReadEEPROM(Card, 1);
379                 Card->MacAddr[2] = macword & 0xFF;
380                 Card->MacAddr[3] = macword >> 8;
381                 macword = E1000_int_ReadEEPROM(Card, 2);
382                 Card->MacAddr[4] = macword & 0xFF;
383                 Card->MacAddr[5] = macword >> 8;
384         }
385         Log_Log("E1000", "%p: MAC Address %02x:%02x:%02x:%02x:%02x:%02x",
386                 Card,
387                 Card->MacAddr[0], Card->MacAddr[1],
388                 Card->MacAddr[2], Card->MacAddr[3],
389                 Card->MacAddr[4], Card->MacAddr[5]);
390         
391         // --- Prepare for RX ---
392         LOG("RX Preparation");
393         Card->RXDescs = (void*)MM_AllocDMA(1, 64, NULL);
394         if( !Card->RXDescs ) {
395                 LEAVE('i', 2);
396                 return 2;
397         }
398         if( DrvUtil_AllocBuffers(Card->RXBuffers, NUM_RX_DESC, 64, RX_DESC_BSIZE) ) {
399                 LEAVE('i', 3);
400                 return 3;
401         }
402         for( int i = 0; i < NUM_RX_DESC; i ++ )
403         {
404                 Card->RXDescs[i].Buffer = MM_GetPhysAddr(Card->RXBuffers[i]);
405                 Card->RXDescs[i].Status = 0;    // Clear RXD_STS_DD, gives it to the card
406                 Card->RXBackHandles[i] = Card;
407         }
408         
409         REG64(Card, REG_RDBAL) = MM_GetPhysAddr((void*)Card->RXDescs);
410         REG32(Card, REG_RDLEN) = NUM_RX_DESC * 16;
411         REG32(Card, REG_RDH) = 0;
412         REG32(Card, REG_RDT) = NUM_RX_DESC;
413         // Hardware size, Multicast promisc, Accept broadcast, Interrupt at 1/4 Rx descs free
414         REG32(Card, REG_RCTL) = RX_DESC_BSIZEHW | RCTL_MPE | RCTL_BAM | RCTL_RDMTS_1_4;
415         Card->FirstUnseenRXD = 0;
416         Card->LastUnseenRXD = 0;
417
418         // --- Prepare for TX ---
419         LOG("TX Preparation");
420         Card->TXDescs = (void*)MM_AllocDMA(1, 64, NULL);
421         if( !Card->RXDescs ) {
422                 LEAVE('i', 4);
423                 return 4;
424         }
425         for( int i = 0; i < NUM_TX_DESC; i ++ )
426         {
427                 Card->TXDescs[i].Buffer = 0;
428                 Card->TXDescs[i].CMD = 0;
429         }
430         REG64(Card, REG_TDBAL) = MM_GetPhysAddr((void*)Card->TXDescs);
431         REG32(Card, REG_TDLEN) = NUM_TX_DESC * 16;
432         REG32(Card, REG_TDH) = 0;
433         REG32(Card, REG_TDT) = 0;
434         // Enable, pad short packets
435         REG32(Card, REG_TCTL) = TCTL_EN | TCTL_PSP | (0x0F << TCTL_CT_ofs) | (0x40 << TCTL_COLD_ofs);
436         Card->FirstFreeTXD = 0;
437
438         // -- Prepare Semaphores
439         Semaphore_Init(&Card->FreeTxDescs, NUM_TX_DESC, NUM_TX_DESC, "E1000", "TXDescs");
440         Semaphore_Init(&Card->AvailPackets, 0, NUM_RX_DESC, "E1000", "RXDescs");
441
442         // --- Prepare for full operation ---
443         LOG("Starting card");
444         REG32(Card, REG_CTRL) = CTRL_SLU|CTRL_ASDE;     // Link up, auto speed detection
445         REG32(Card, REG_IMS) = 0x1F6DC; // Interrupt mask
446         (void)REG32(Card, REG_ICR);     // Discard pending interrupts
447         REG32(Card, REG_RCTL) |= RCTL_EN;
448         LEAVE('i', 0);
449         return 0;
450 }
451
452 Uint16 E1000_int_ReadEEPROM(tCard *Card, Uint8 WordIdx)
453 {
454         REG32(Card, REG_EERD) = ((Uint32)WordIdx << 8) | 1;
455         Uint32  tmp;
456         while( !((tmp = REG32(Card, REG_EERD)) & (1 << 4)) ) {
457                 // TODO: use something like Time_MicroDelay instead
458                 Time_Delay(1);
459         }
460         
461         return tmp >> 16;
462 }

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