📄 net_3c509.cxx
字号:
out8(0x0, id_port); /* move to ID_WAIT state */ Machine::SpinWaitMs(1); /* let things settle */ { /* Output the card ID sequence: */ uint8_t bVal = 0xFF; for (uint8_t loop = 255; loop; loop--) { out8(bVal, id_port); if (bVal & 0x80) { bVal <<= 1; bVal ^= 0xCF; } else bVal <<= 1; } }} static voidISA_Probe(AutoConf * ac){#ifdef CONFIG_ISA /* 3c509's ship with ISA PnP enabled by default, which means that * most OSes cannot autoconfigure them correctly. We want to use * non-PnP configuration, since I have not had time to grok the PnP * device configuration tree, so tell the PnP mechanism to bug off * and leave us alone: */ out8(PnpSelConfigCtrl, PnpAddress); /* select PnP config ctrl register */ out8(ElinkSetContention, PnpWrite); /* and disable PnP config */ Machine::SpinWaitMs(1); /* let things settle */ /* Figure out where the 3c509 ID port went: */ for (id_port = 0x100; id_port < 0x200; id_port += 0x10) { if (IoRegion::Allocate(id_port, 0x01, "3c509 contention")) break; } if (id_port >= 0x200) { MsgLog::dprintf(true, "Unable to configure ISA 3c509 -- " "no available ID port\n"); return; } /* If we did a warm boot, then we need to force the card to do a * total reset to reset the previously tagged values. * Unfortunately, this will completely reset the card, which will * have the effect of restoring it to PnP mode too. */ out8(0x0, id_port); /* set ID PORT value */ Machine::SpinWaitMs(1); /* let things settle */ /* The global reset doesn't work unless we first put the card in a * receptive state such as ID_WAIT */ out8(0x0, id_port); Machine::SpinWaitMs(1); /* let things settle */ out8(IdGlobalReset, id_port); Machine::SpinWaitMs(1); /* let things settle */ /* Get the card(s) out of PnP mode again: */ out8(PnpSelConfigCtrl, PnpAddress); /* select PnP config ctrl register */ out8(ElinkSetContention, PnpWrite); /* and disable PnP config */ Machine::SpinWaitMs(1); /* let things settle */ /* ALL of the cards are now reset, which implies that they have a * ZERO in their tag registers. Identify all of the cards by * tagging them: */ /* NOW we can begin the ID sequence for real: */ for (uint8_t card = 0; ; card++) { IdentifySequence(); /* If we have tagged any cards at all, make the cards that have * already been tagged drop out of the contention sequence: */ if (card == 0) out8(IdSetTagReg + 0, id_port); /* set all tags to 0 */ else out8(IdTestAdapter + 0, id_port); /* Read the manufacturer ID. If we don't get what we expect we * are done with ISA probe: */ if (IsaIdRdEEPROM(id_port, 7) != MANU_3COM) { MsgLog::dprintf(false, "3c509 not found (manid)\n"); break; } NetInterface *ni = NetInterface::Alloc(); /* Contention resolution protocol: check link addr 0..2, address * config register, resource config register, software config register */ /* Get the adapter link-level address: */ ni->info.niAddrLen = 6; for (int i = 0; i < 3; i++) { uint16_t hw = IsaIdRdEEPROM(id_port, i); ni->info.niAddr[i*2] = (hw >> 8) & 0xffu; ni->info.niAddr[ i*2 + 1 ] = hw & 0xffu; } uint16_t prodId = IsaIdRdEEPROM(id_port, 0x03); uint16_t addrCfg = IsaIdRdEEPROM(id_port, 0x08); uint16_t rsrcCfg = IsaIdRdEEPROM(id_port, 0x09); (void) IsaIdRdEEPROM(id_port, 0x0d); /* SW config */ uint8_t ioAddrBits = addrCfg & AddrCfgIoBase; ni->tagValue = card + 1; /* remember tag value */ /* Output the set tag command: */ out8(IdSetTagReg + ni->tagValue, id_port); ni->irq = (rsrcCfg & RsrcCfgIrq) >> 12; ni->ioAddr = ioAddrBits * 0x10 + 0x200; ni->addr = 0; ni->len = 0; ni->xcvr = (addrCfg & AddrCfgXcvr) >> 14; ni->name = "EtherLink III (ISA)"; ni->devClass = DEV_NET_ENET; ni->Invoke = Invoke; ni->info.niStatus = 0; ni->watchDog.client_ptr = ni; ni->updateStats = UpdateStatistics; MsgLog::dprintf(false, "Found ISA 3c509 io=0x%x, irq=%d prod=0x%04x" " link address is %02x:%02x:%02x:%02x:%02x:%02x\n", ni->ioAddr, ni->irq, prodId, ni->info.niAddr[0], ni->info.niAddr[1], ni->info.niAddr[2], ni->info.niAddr[3], ni->info.niAddr[4], ni->info.niAddr[5]);#if 0 /* Reserve I/O port addresses used by adapter. */ if ( IoRegion::Allocate(ni->ioAddr, 0x10, "3c509") == false ) { MsgLog::dprintf(true, "Unable to enable 3c509 at io=0x%x: " "port range is taken\n", ni->ioAddr); continue; } /* Activate adapter at preconfigured I/O base address. After reset * all interrupts are masked, so the device should not generate any. */ out8(IdActivate | ioAddrBits, id_port);#endif ac->present = true; }#else /* This will peephole out -- it suppresses a compiler warning. */ ac->present = ac->present;#endif}/* Probe for EtherLink III family cards. Note that UNLIKE the * corresponding UNIX logic, this code is probing for the device * CLASS, not for device instances -- we do not have a per-instance * autoconfiguration structure, as the network interface capability * carries an instance number. The job of probe is simply to locate * the instances so that we can later attach them. */static voidProbe(struct AutoConf * ac){ /* No EtherLink III family cards are present until proven otherwise. */ ac->present = false; EISA_Probe(ac); MCA_Probe(ac); ISA_Probe(ac);}/* We assume that by attachment time the autoconfigurator domain has * taken it's shot at the device configuration information, and that * the attachment will either entirely succeed or entirely fail. * * WARNING: There is a danger in the current implementation. I do not * understand whether the ID sequence interrupts the in-progress * activities of the cards. If so, activating one card requires * waiting for the others to quiesce. This code does not do so. In * particular I am concerned about diverting the processing of an * incoming interrupt. */static voidAttach(NetInterface* ni){ MsgLog::dprintf(false, "Attaching ISA 3c509 io=0x%x, irq=%d tag=%d" " link address is %02x:%02x:%02x:%02x:%02x:%02x\n", ni->ioAddr, ni->irq, ni->tagValue, ni->info.niAddr[0], ni->info.niAddr[1], ni->info.niAddr[2], ni->info.niAddr[3], ni->info.niAddr[4], ni->info.niAddr[5]); if (ni->info.niStatus & NI_ATTACHED) { MsgLog::dprintf(true, "NI 0x%08x already attached\n", ni); return; } /* Reserve I/O port addresses used by adapter. */ if ( IoRegion::Allocate(ni->ioAddr, 0x0f, "3c509") == false ) { MsgLog::dprintf(true, "Unable to enable 3c509 at io=0x%x: " "port range is taken\n", ni->ioAddr); return; } /* Reserve the IRQ: */ IntAction *ia = new (0) IntAction(ni->irq, "3c509", HandleInterrupt, (uint32_t) ni); if ( IRQ::WireExclusive(ia) == false ) { IoRegion::Release(ni->ioAddr, 0x0f); MsgLog::dprintf(true, "Unable to enable 3c509 at io=0x%x: " "irq %d is taken\n", ni->ioAddr, ni->irq); return; }#if 0 /* DANGER, Will Robinson! -- this sequence keeps interrupts disabled * for several milliseconds, which is BAD. */ IRQ::DISABLE();#endif IdentifySequence(); /* Select the adapter we actually want -- leave the rest alone. */ out8(IdTestAdapter + ni->tagValue, id_port); /* Activate adapter at preconfigured I/O base address. After reset * all interrupts are masked, so the device should not generate any. */#if 1 out8(IdActivate | (ni->ioAddr >> 4), id_port);#else out8(IdActivatePreconf, id_port);#endif Machine::SpinWaitMs(1); #if 0 IRQ::ENABLE();#endif /* Verify that it ended up in the right place by reading the * manufacturer ID from window zero: */ SetWindow(ni, 0); uint16_t manid = in16(ni->ioAddr + El3ManufacturerID); if ( manid != MANU_3COM ) { MsgLog::dprintf(true, "Alleged adapter does not respond with" " proper manufacturer ID (got 0x%04x)\n", manid); return; } /* Set the adaptor IRQ to 0: */ out16(0x0f00, ni->ioAddr + Wn0Irq); /* Interrupt is reserved, but not enabled at this point. */ ni->info.niStatus |= NI_ATTACHED; Enable(ni);}static voidAutoAttach(struct AutoConf * /* ac */){ for (uint32_t i = 0; i < KTUNE_NNETDEV; i++) { NetInterface *ni; if ( (ni = NetInterface::Get(i)) == 0 ) continue; if (ni->updateStats != UpdateStatistics) continue; Attach(ni); }}static voidHydrant(Timer* t){ NetInterface *ni = (NetInterface *) t->client_ptr; SetWindow(ni, 1); MsgLog::dprintf(false, "%s: elink xmit timeout. TxStatus: 0x%02x" " Status 0x%04x tx txFifo room %d\n", ni->name, in8(ni->ioAddr + Wn1TxStatus), in16(ni->ioAddr + El3Status), in16(ni->ioAddr + Wn1TxFree)); ni->stats.txWatchdog++; OutCmd(ni, TxReset, true); /* long-running cmd */ OutCmd(ni, TxEnable); ni->wrQ.WakeAll();}static voidInvoke(NetInterface *ni, Invocation& inv){#ifndef OPTION_PURE_ENTRY_STRINGS Thread::CurContext()->SetupEntryString(inv);#endif#ifndef OPTION_PURE_EXIT_STRINGS inv.invokee->SetupExitString(inv, inv.validLen);#endif COMMIT_POINT(); switch (inv.entry.code) { case OC_NI_Read: { ReadPacket(ni, inv); break; } case OC_NI_Write: { if (inv.entry.len >= MIN_ENET_PACKET_SZ && inv.entry.len <= MAX_ENET_PACKET_SZ) WritePacket(ni, inv); else inv.exit.code = RC_RequestError; break; } case OC_NI_MultiRead: { MultiReadPacket(ni, inv); break; } case OC_NI_MultiWrite: { inv.exit.code = RC_UnknownRequest; return; } case OC_NI_GetInfo: { inv.CopyOut(sizeof(ni->info), &ni->info); return; } case OC_NI_GetStats: { inv.CopyOut(sizeof(ni->stats), &ni->stats); return; } case OC_NI_Reset: { inv.exit.code = RC_UnknownRequest; return; } default: inv.exit.code = RC_UnknownRequest; }}/* #define ICMP_ECHO_TESTING */#ifdef ICMP_ECHO_TESTING#include <eros/endian.h>#if !defined(MODERATELY_SLOW)/* * Checksum routine for Internet Protocol family headers. * * This routine is very heavily used in the network * code and should be modified for each CPU to be as fast as possible. * * This implementation is 386 version. */#define REDUCE {sum = (sum & 0xffff) + (sum >> 16);}#define ADDCARRY {if (sum > 0xffff) sum -= 0xffff;}#define SWAP {sum <<= 8;}#define ADVANCE(x) {w += x; mlen -= x;}/* * Thanks to gcc we don't have to guess * which registers contain sum & w. */#define Asm __asm __volatile#define ADD(n) Asm("addl " #n "(%2),%0" : "=r" (sum) : "0" (sum), "r" (w))#define ADC(n) Asm("adcl " #n "(%2),%0" : "=r" (sum) : "0" (sum), "r" (w))#define MOP Asm("adcl $0,%0" : "=r" (sum) : "0" (sum))#define UNSWAP Asm("roll $8,%0" : "=r" (sum) : "0" (sum))#define AOPTION_DDBYTE {sum += *w; SWAP; byte_swapped ^= 1;}#define ADDWORD {sum += *(u_short *)w;}intin_cksum(uint16_t *buf, register int len){ register u_char *w = (u_char *) buf; register unsigned sum = 0; register int mlen = len; int byte_swapped = 0; len -= mlen; if (mlen < 16) goto short_mbuf; /* * Force to long boundary so we do longword aligned * memory operations */ if ((3 & (long)w) != 0) { REDUCE; if ((1 & (long)w) != 0) { AOPTION_DDBYTE; ADVANCE(1); } if ((2 & (long)w) != 0) { ADDWORD; ADVANCE(2); } } /* * Align 4 bytes past a 16-byte cache line boundary. */ if ((4 & (long)w) == 0) { ADD(0); MOP; ADVANCE(4); } if ((8 & (long)w) != 0) { ADD(0); ADC(4); MOP; ADVANCE(8); } /* * Do as much of the checksum as possible 32 bits at at time. * In fact, this loop is unrolled to make overhead from * branches &c small. */ while ((mlen -= 32) >= 0) { /* * Add with carry 16 words and fold in the last carry * by adding a 0 with carry. * * We aligned the pointer above so that the out-of- * order operations will cause the next cache line to * be preloaded while we finish with the current one. */ ADD(12); ADC(0); ADC(4); ADC(8); ADC(28); ADC(16); ADC(20); ADC(24); MOP; w += 32; } mlen += 32; if (mlen >= 16) { ADD(12); ADC(0); ADC(4); ADC(8); MOP; ADVANCE(16); }short_mbuf: if (mlen >= 8) { ADD(0); ADC(4); MOP; ADVANCE(8); } if (mlen >= 4) { ADD(0); MOP; ADVANCE(4); } if (mlen > 0) { REDUCE; if (mlen >= 2) { ADDWORD; ADVANCE(2); } if (mlen >= 1) { AOPTION_DDBYTE; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -