2 * Acess2 E1000 Network Driver
3 * - By John Hodge (thePowersGang)
6 * - Intel 8254x Network Card Driver (core)
9 #define VERSION VER2(0,1)
14 #include <IPStack/include/adapters_api.h>
15 #include <timers.h> // Time_Delay
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
27 const int ciNumSupportedCards = sizeof(caSupportedCards)/sizeof(caSupportedCards[0]);
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);
39 MODULE_DEFINE(0, VERSION, E1000, E1000_Install, E1000_Cleanup, NULL);
40 tIPStack_AdapterType gE1000_AdapterType = {
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
50 int E1000_Install(char **Arguments)
53 for( int modelidx = 0; modelidx < ciNumSupportedCards; modelidx ++ )
55 const struct sSupportedCard *cardtype = &caSupportedCards[modelidx];
56 card_count += PCI_CountDevices(cardtype->Vendor, cardtype->Device);
58 LOG("card_count = %i", card_count);
59 if( card_count == 0 ) {
60 LOG("Zero cards located");
61 return MODULE_ERR_NOTNEEDED;
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;
73 for( int modelidx = 0; modelidx < ciNumSupportedCards; modelidx ++ )
75 const struct sSupportedCard *cardtype = &caSupportedCards[modelidx];
76 for( int id = -1, i = 0; (id = PCI_GetDevice(cardtype->Vendor, cardtype->Device, i)) != -1; i ++ )
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);
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);
89 Log_Debug("E1000", "Card %i: %P IRQ %i", card_idx, card->MMIOBasePhys, card->IRQ);
91 if( E1000_int_InitialiseCard(card) ) {
92 Log_Warning("E1000", "Initialisation of card #%i failed", card_idx);
93 return MODULE_ERR_MALLOC;
96 card->IPStackHandle = IPStack_Adapter_Add(&gE1000_AdapterType, card, card->MacAddr);
102 int E1000_Cleanup(void)
107 void E1000_int_ReleaseRXD(void *Arg, size_t HeadLen, size_t FootLen, const void *Data)
109 tCard **cardptr = Arg;
110 tCard *Card = *cardptr;
111 int rxd = (Arg - (void*)Card->RXBackHandles) / sizeof(void*);
113 LOG("RXD %p %i being released", Card, rxd);
114 ASSERT(rxd >= 0 && rxd < NUM_RX_DESC);
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) ) {
121 if( rxd == NUM_RX_DESC )
124 REG32(Card, REG_RDT) = rxd;
125 LOG("Updated RDT=%i", rxd);
127 Mutex_Release(&Card->lRXDescs);
130 tIPStackBuffer *E1000_WaitForPacket(void *Ptr)
134 if( Semaphore_Wait(&Card->AvailPackets, 1) != 1 )
139 Mutex_Acquire(&Card->lRXDescs);
140 int first_rxd = Card->FirstUnseenRXD;
141 int last_rxd = first_rxd;
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 )
149 last_rxd = (last_rxd + 1) % NUM_RX_DESC;
151 Card->FirstUnseenRXD = (last_rxd + 1) % NUM_RX_DESC;
152 Mutex_Release(&Card->lRXDescs);
154 LOG("nDesc = %i, first_rxd = %i", nDesc, first_rxd);
155 tIPStackBuffer *ret = IPStack_Buffer_CreateBuffer(nDesc);
157 for( int i = 0; i < nDesc; i ++ )
159 IPStack_Buffer_AppendSubBuffer(ret, 0, Card->RXDescs[rxd].Length, Card->RXBuffers[rxd],
160 E1000_int_ReleaseRXD, &Card->RXBackHandles[rxd]);
167 int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
171 ENTER("pPtr pBuffer", Ptr, Buffer);
176 // Count sub-buffers (including splitting cross-page entries)
178 while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
180 if( len > PAGE_SIZE ) {
181 LOG("len=%i > PAGE_SIZE", len);
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);
192 // Request set of TX descriptors
193 int rv = Semaphore_Wait(&Card->FreeTxDescs, nDesc);
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;
203 LOG("first_txd = %i, last_txd = %i", first_txd, last_txd);
208 while( (idx = IPStack_Buffer_GetBuffer(Buffer, idx, &len, &ptr)) != -1 )
210 //Debug_HexDump("E100 SendPacket", ptr, len);
211 if( MM_GetPhysAddr(ptr) + len-1 != MM_GetPhysAddr((char*)ptr + len-1) )
213 size_t remlen = PAGE_SIZE - ((tVAddr)ptr & (PAGE_SIZE-1));
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;
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;
228 volatile tTXDesc *txdp = &Card->TXDescs[txd];
229 txdp->Buffer = MM_GetPhysAddr(ptr);
231 txdp->CMD = TXD_CMD_RS;
232 LOG("%P: %llx %x %x", MM_GetPhysAddr((void*)txdp), txdp->Buffer, txdp->Length, txdp->CMD);
234 txd = (txd + 1) % NUM_TX_DESC;
236 Card->TXDescs[last_txd].CMD |= TXD_CMD_EOP|TXD_CMD_IDE|TXD_CMD_IFCS;
237 Card->TXSrcBuffers[last_txd] = Buffer;
239 __sync_synchronize();
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);
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");
257 // Wait for completion (lock will block, then release straight away)
258 IPStack_Buffer_LockBuffer(Buffer);
259 IPStack_Buffer_UnlockBuffer(Buffer);
261 // TODO: Check status bits
267 void E1000_IRQHandler(int Num, void *Ptr)
271 Uint32 icr = REG32(Card, REG_ICR);
274 LOG("icr = %x", icr);
276 // Transmit descriptor written
277 if( (icr & ICR_TXDW) || (icr & ICR_TXQE) )
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 )
288 if(Card->TXDescs[txd].Status & TXD_STS_DD) {
289 nReleasedAtLastDD = nReleased;
293 if(txd == NUM_TX_DESC)
296 if( nReleasedAtLastDD )
299 txd = Card->LastFreeTXD;
300 LOG("TX unlocking range %i-%i", txd, idxOfLastDD);
301 while( txd != (idxOfLastDD+1)%NUM_TX_DESC )
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;
309 if(txd == NUM_TX_DESC)
313 Card->LastFreeTXD = txd;
314 Semaphore_Signal(&Card->FreeTxDescs, nReleasedAtLastDD);
315 LOG("nReleased = %i", nReleasedAtLastDD);
319 LOG("No completed TXDs");
325 // Link status change
327 // TODO: Detect link drop/raise and poke IPStack
335 // Pending packet (s)
339 LOG("RX %i:%i", Card->LastUnseenRXD, Card->FirstUnseenRXD);
340 while( (Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_DD) )
342 if( Card->RXDescs[Card->LastUnseenRXD].Status & RXD_STS_EOP )
344 Card->LastUnseenRXD ++;
345 if( Card->LastUnseenRXD == NUM_RX_DESC )
346 Card->LastUnseenRXD = 0;
348 if( Card->LastUnseenRXD == Card->FirstUnseenRXD )
351 Semaphore_Signal(&Card->AvailPackets, nPackets);
352 LOG("nPackets = %i", nPackets);
355 // Transmit Descriptor Low Threshold hit
356 if( icr & ICR_TXD_LOW )
361 // Receive Descriptor Minimum Threshold Reached
362 // - We're reading too slow
363 if( icr & ICR_RXDMT0 )
365 LOG("RX descs running out");
368 icr &= ~(ICR_RXT0|ICR_LSC|ICR_TXQE|ICR_TXDW|ICR_TXD_LOW|ICR_RXDMT0);
370 Log_Warning("E1000", "Unhandled ICR bits 0x%x", icr);
373 // TODO: Move this function into Kernel/drvutil.c
375 * \brief Allocate a set of buffers in hardware mapped space
377 * Allocates \a NumBufs buffers using shared pages (if \a BufSize is less than a page) or
378 * as a set of contiugious allocations.
380 int DrvUtil_AllocBuffers(void **Buffers, int NumBufs, int PhysBits, size_t BufSize)
382 if( BufSize >= PAGE_SIZE )
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;
394 const int bufs_per_page = PAGE_SIZE / BufSize;
395 ASSERT(bufs_per_page * BufSize == PAGE_SIZE);
397 for( int i = 0; i < NumBufs; i ++ )
400 page = (void*)MM_AllocDMA(1, PhysBits, NULL);
401 if( !page ) return 1;
403 Buffers[i] = (char*)page + ofs;
405 if( ofs >= PAGE_SIZE )
412 int E1000_int_InitialiseCard(tCard *Card)
414 ENTER("pCard", Card);
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);
424 // --- Read MAC address from EEPROM ---
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;
437 Log_Log("E1000", "%p: MAC Address %02x:%02x:%02x:%02x:%02x:%02x",
439 Card->MacAddr[0], Card->MacAddr[1],
440 Card->MacAddr[2], Card->MacAddr[3],
441 Card->MacAddr[4], Card->MacAddr[5]);
443 // --- Prepare for RX ---
444 LOG("RX Preparation");
445 Card->RXDescs = (void*)MM_AllocDMA(1, 64, NULL);
446 if( !Card->RXDescs ) {
450 if( DrvUtil_AllocBuffers(Card->RXBuffers, NUM_RX_DESC, 64, RX_DESC_BSIZE) ) {
454 for( int i = 0; i < NUM_RX_DESC; i ++ )
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;
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;
470 // --- Prepare for TX ---
471 LOG("TX Preparation");
472 Card->TXDescs = (void*)MM_AllocDMA(1, 64, NULL);
473 if( !Card->RXDescs ) {
477 LOG("Card->RXDescs = %p [%P]", Card->TXDescs, MM_GetPhysAddr((void*)Card->TXDescs));
478 for( int i = 0; i < NUM_TX_DESC; i ++ )
480 Card->TXDescs[i].Buffer = 0;
481 Card->TXDescs[i].CMD = 0;
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;
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");
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;
505 Uint16 E1000_int_ReadEEPROM(tCard *Card, Uint8 WordIdx)
507 REG32(Card, REG_EERD) = ((Uint32)WordIdx << 8) | 1;
509 while( !((tmp = REG32(Card, REG_EERD)) & (1 << 4)) ) {
510 // TODO: use something like Time_MicroDelay instead