The Pedigree Project 0.1
Ne2k.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "Ne2k.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/machine/Device.h"
24#include "pedigree/kernel/machine/IrqManager.h"
25#include "pedigree/kernel/machine/Machine.h"
26#include "pedigree/kernel/machine/Network.h"
27#include "pedigree/kernel/network/IpAddress.h"
28#include "pedigree/kernel/network/MacAddress.h"
29#include "pedigree/kernel/process/Thread.h"
30#include "pedigree/kernel/processor/IoBase.h"
31#include "pedigree/kernel/processor/Processor.h"
32#include "pedigree/kernel/processor/ProcessorInformation.h"
33#include "pedigree/kernel/time/Time.h"
34#include "pedigree/kernel/utilities/MemoryPool.h"
35#include "pedigree/kernel/utilities/Vector.h"
36#include "pedigree/kernel/utilities/utility.h"
37
38#include "Ne2kConstants.h"
39#include "modules/system/network-stack/NetworkStack.h"
40
41// #define NE2K_NO_THREADS
42
43namespace {
44constexpr uint8_t CommandPage0Stop = E8390_NODMA | E8390_PAGE0 | E8390_STOP;
45constexpr uint8_t CommandPage0Start = E8390_NODMA | E8390_PAGE0 | E8390_START;
46constexpr uint8_t CommandPage1Stop = E8390_NODMA | E8390_PAGE1 | E8390_STOP;
47constexpr uint8_t CommandPage1Start = E8390_NODMA | E8390_PAGE1 | E8390_START;
48constexpr uint8_t CommandRemoteRead = E8390_RREAD | E8390_PAGE0 | E8390_START;
49constexpr uint8_t CommandRemoteWrite = E8390_RWRITE | E8390_PAGE0 | E8390_START;
50constexpr uint8_t CommandTransmit = E8390_NODMA | E8390_TRANS | E8390_PAGE0 | E8390_START;
51
52constexpr uint8_t InterruptReceive = 0x01;
53constexpr uint8_t InterruptTransmit = 0x02;
54constexpr uint8_t InterruptReceiveError = 0x04;
55constexpr uint8_t InterruptTransmitError = 0x08;
56constexpr uint8_t InterruptOverflow = 0x10;
57constexpr uint8_t InterruptCounters = 0x20;
58constexpr uint8_t InterruptRemoteDmaComplete = 0x40;
59constexpr uint8_t InterruptReset = 0x80;
60constexpr uint8_t EnabledInterrupts = InterruptReceive | InterruptReceiveError |
61 InterruptTransmitError | InterruptOverflow |
62 InterruptCounters;
63
64constexpr size_t RemoteDmaPollLimit = 1000000;
65constexpr size_t ResetPollLimit = 100000;
66constexpr size_t MinimumPacketLength = 14;
67constexpr size_t MaximumPacketLength = 1600;
68} // namespace
69
71 : Network(pDev),
72 m_pBase(0),
73 m_NextPacket(0),
74 m_PacketQueueSize(0),
75 m_PacketQueue(),
76 m_PacketQueueLock(),
77 m_DmaLock(),
78 m_IrqId(0),
79 m_Stopping(false),
80 m_NetworkRegistered(false),
81 m_ReceiveThread() {
82 setSpecificType(String("ne2k-card"));
83
84 // grab the ports
85 m_pBase = m_Addresses[0]->m_Io;
86
87 // Reset the card, and clear interrupts
88 // m_pBase->write8(m_pBase->read8(NE_RESET), NE_RESET);
89 // while((m_pBase->read8(NE_ISR) & 0x80) == 0);
90 // m_pBase->write8(0xff, NE_ISR);
91
92 // reset command
93 m_pBase->write8(0x21, NE_CMD);
94
95 // 16-bit transfer, monitor to avoid recv, loopback just in case
96 // because we don't want to receive packets yet
97 m_pBase->write8(0x09, NE_DCR);
98 m_pBase->write8(0x20, NE_RCR);
99 m_pBase->write8(0x02, NE_TCR);
100
101 // turn off interrupts
102 m_pBase->write8(0xff, NE_ISR);
103 m_pBase->write8(0x00, NE_IMR);
104
105 // get the MAC from PROM
106 m_pBase->write8(0x00, NE_RSAR0);
107 m_pBase->write8(0x00, NE_RSAR1);
108
109 m_pBase->write8(32, NE_RBCR0); // 32 bytes of data
110 m_pBase->write8(0, NE_RBCR1);
111
112 m_pBase->write8(0x0a, NE_CMD); // remote read, STOP
113
114 uint16_t prom[16];
115 int i;
116 for (i = 0; i < 16; i++)
117 prom[i] = m_pBase->read16(NE_DATA);
118
119 // set the MAC address in the card itself
120 m_pBase->write8(0x61, NE_CMD);
121 for (i = 0; i < 6; i++) {
122 m_StationInfo.mac.setMac(prom[i] & 0xff, i);
123 m_pBase->write8(prom[i] & 0xff, NE_PAR + i);
124 }
125
126 WARNING("NE2K: MAC is " << m_StationInfo.mac[0] << ":" << m_StationInfo.mac[1] << ":"
127 << m_StationInfo.mac[2] << ":" << m_StationInfo.mac[3] << ":"
128 << m_StationInfo.mac[4] << ":" << m_StationInfo.mac[5] << ".");
129
130 // reset current page, put the card into normal mode, and set
131 // packet buffer information
132 m_pBase->write8(0x61, NE_CMD);
133 m_pBase->write8(PAGE_RX + 1, NE_CURR);
134
135 m_NextPacket = PAGE_RX + 1;
136
137 m_pBase->write8(0x21, NE_CMD);
138
139 m_pBase->write8(PAGE_RX, NE_PSTART);
140 m_pBase->write8(PAGE_RX, NE_BNDRY);
141 m_pBase->write8(PAGE_STOP, NE_PSTOP);
142
143 // accept multicast, broadcast, and runt packets (<64 bytes)
145 m_pBase->write8(0x14, NE_RCR);
146 m_pBase->write8(0x00, NE_TCR);
147
148 // Accept all multicast packets. Once we have an API for multicast
149 // subscription this will be different, as we may not want to receive every
150 // single multicast packet that arrives.
151 uint8_t tmp = m_pBase->read8(NE_CMD);
152 m_pBase->write8(tmp | 0x40, NE_CMD);
153 for (i = 0; i < MAR_SIZE; i++)
154 m_pBase->write8(0xFF, NE_MAR + i);
155 m_pBase->write8(tmp, NE_CMD);
156
157// register the packet queue handler before we install the IRQ
158#if THREADS
159 Thread* pThread = new Thread(Processor::information().getCurrentThread()->getParent(),
160 &trampoline, reinterpret_cast<void*>(this));
161 pThread->setName("NE2K receive worker");
162 m_ReceiveThread.adopt(pThread);
163#endif
164
165 // install the IRQ
166 NOTICE("NE2K: IRQ is " << getInterruptNumber());
167 m_IrqId = Machine::instance().getIrqManager()->registerPciIrqHandler(
168 static_cast<IrqHandler*>(this), this, IrqPolicy::pciIntxThreaded());
169 if (!m_IrqId) {
170 ERROR("NE2K: could not register its PCI interrupt");
171 m_pBase->write8(CommandPage0Stop, NE_CMD);
172 m_pBase->write8(0x00, NE_IMR);
173 m_Stopping = true;
174 m_ReceiveThread.stop();
175 return;
176 }
177
178 // clear interrupts and enable the ones we want
179 m_pBase->write8(0xff, NE_ISR);
180 m_pBase->write8(EnabledInterrupts, NE_IMR); // No IRQ for successful transmission.
181
182 // start the card working properly
183 m_pBase->write8(CommandPage0Start, NE_CMD);
184
186 m_NetworkRegistered = true;
187}
188
189Ne2k::~Ne2k() {
190 {
191 LockGuard<Mutex> dmaGuard(m_DmaLock);
192 m_Stopping = true;
193 // NE_IMR aliases a multicast register outside page zero. Normalise the
194 // page while callback and transmit register access is excluded.
195 m_pBase->write8(CommandPage0Stop, NE_CMD);
196 m_pBase->write8(0x00, NE_IMR);
197 m_pBase->write8(0x00, NE_RBCR0);
198 m_pBase->write8(0x00, NE_RBCR1);
199 }
200 if (m_IrqId && !Machine::instance().getIrqManager()->unregisterHandler(m_IrqId, this)) {
201 FATAL("NE2K teardown could not unregister its IRQ callback.");
202 }
203 m_IrqId = 0;
204
205 m_ReceiveThread.stop();
206 if (m_NetworkRegistered) {
208 m_NetworkRegistered = false;
209 }
210
211 LockGuard<Spinlock> guard(m_PacketQueueLock);
212 while (m_PacketQueue.count()) {
213 packet* pending = m_PacketQueue.popFront();
214 if (pending) {
215 if (pending->ptr) {
216 NetworkStack::instance().getMemPool().free(pending->ptr);
217 }
218 delete pending;
219 }
220 }
221}
222
223bool Ne2k::send(size_t nBytes, uintptr_t buffer) {
224 if (!nBytes || nBytes > MaximumPacketLength) {
225 ERROR("NE2K: invalid transmit packet length " << Dec << nBytes << Hex);
226 return false;
227 }
228
229 LockGuard<Mutex> dmaGuard(m_DmaLock);
230 if (m_Stopping || !m_IrqId) {
231 return false;
232 }
233
234 const size_t transmitLength = nBytes < 64 ? 64 : nBytes;
235 const size_t dmaLength = (transmitLength + 1) & ~static_cast<size_t>(1);
236
237 // A second upload must not overwrite the single transmit page while the
238 // 8390 is still sending from it.
239 bool transmitterIdle = false;
240 for (size_t transmitPoll = 0; transmitPoll < RemoteDmaPollLimit; ++transmitPoll) {
241 if (!(m_pBase->read8(NE_CMD) & E8390_TRANS)) {
242 transmitterIdle = true;
243 break;
244 }
246 }
247 if (!transmitterIdle) {
248 ERROR("NE2K: transmitter did not become idle");
249 resetController();
250 return false;
251 }
252
253 // length & address for the write
254 m_pBase->write8(CommandPage0Start, NE_CMD);
255 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
256 m_pBase->write8(0, NE_RSAR0);
257 m_pBase->write8(PAGE_TX, NE_RSAR1);
258 m_pBase->write8(dmaLength & 0xff, NE_RBCR0);
259 m_pBase->write8(dmaLength >> 8, NE_RBCR1);
260 m_pBase->write8(CommandRemoteWrite, NE_CMD);
261
262 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
263 size_t i;
264 for (i = 0; (i + 1) < nBytes; i += 2)
265 m_pBase->write16(data[i / 2], NE_DATA);
266
267 // handle odd byte
268 if (nBytes & 1) {
269 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(buffer);
270 m_pBase->write16(bytes[i], NE_DATA);
271 i += 2;
272 }
273
274 // Pad short and odd-sized transfers without reading beyond the caller's
275 // packet. The transmitter byte count still excludes the DMA alignment.
276 for (; i < dmaLength; i += 2)
277 m_pBase->write16(0, NE_DATA);
278
279 // let it complete
280 if (!waitForRemoteDma()) {
281 ERROR("NE2K: remote DMA write timed out");
282 resetController();
283 return false;
284 }
285 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
286
287 // execute the transmission
288 m_pBase->write8(transmitLength & 0xff, NE_TBCR0);
289 m_pBase->write8(transmitLength >> 8, NE_TBCR1);
290
291 m_pBase->write8(PAGE_TX, NE_TPSR);
292
293 // PTX is not enabled in IMR, so retire a previous completion before TXP
294 // starts a new lifetime. Overflow recovery can then distinguish whether
295 // this transmission completed while the receiver was being stopped.
296 m_pBase->write8(InterruptTransmit | InterruptTransmitError, NE_ISR);
297 m_pBase->write8(CommandTransmit, NE_CMD);
298
299 // success!
300 return true;
301}
302
303bool Ne2k::waitForRemoteDma() {
304 for (size_t i = 0; i < RemoteDmaPollLimit; ++i) {
305 if (m_pBase->read8(NE_ISR) & InterruptRemoteDmaComplete) {
306 return true;
307 }
309 }
310 return false;
311}
312
313bool Ne2k::resetController() {
314 m_pBase->write8(CommandPage0Stop, NE_CMD);
315 m_pBase->write8(0x00, NE_IMR);
316
317 const uint8_t resetLatch = m_pBase->read8(NE_RESET);
318 m_pBase->write8(resetLatch, NE_RESET);
319
320 bool resetComplete = false;
321 for (size_t i = 0; i < ResetPollLimit; ++i) {
322 if (m_pBase->read8(NE_ISR) & InterruptReset) {
323 resetComplete = true;
324 break;
325 }
327 }
328 if (!resetComplete) {
329 ERROR("NE2K: controller reset timed out");
330 m_pBase->write8(CommandPage0Stop, NE_CMD);
331 m_pBase->write8(0x00, NE_IMR);
332 return false;
333 }
334
335 // Re-establish all page-window and ring state. A DMA timeout leaves the
336 // remote count/address registers untrustworthy, so merely clearing RDC is
337 // not sufficient before the next transfer.
338 m_pBase->write8(CommandPage0Stop, NE_CMD);
339 m_pBase->write8(0x09, NE_DCR);
340 m_pBase->write8(0x00, NE_RBCR0);
341 m_pBase->write8(0x00, NE_RBCR1);
342 m_pBase->write8(0x20, NE_RCR);
343 m_pBase->write8(E8390_TXOFF, NE_TCR);
344 m_pBase->write8(PAGE_TX, NE_TPSR);
345 m_pBase->write8(PAGE_RX, NE_PSTART);
346 m_pBase->write8(PAGE_RX, NE_BNDRY);
347 m_pBase->write8(PAGE_STOP, NE_PSTOP);
348 m_pBase->write8(0xff, NE_ISR);
349 m_pBase->write8(0x00, NE_IMR);
350
351 m_pBase->write8(CommandPage1Stop, NE_CMD);
352 for (size_t i = 0; i < 6; ++i) {
353 m_pBase->write8(m_StationInfo.mac[i], NE_PAR + i);
354 }
355 m_pBase->write8(PAGE_RX + 1, NE_CURR);
356 for (size_t i = 0; i < MAR_SIZE; ++i) {
357 m_pBase->write8(0xff, NE_MAR + i);
358 }
359
360 m_NextPacket = PAGE_RX + 1;
361 m_pBase->write8(CommandPage0Stop, NE_CMD);
362 m_pBase->write8(0x14, NE_RCR);
363 m_pBase->write8(E8390_TXCONFIG, NE_TCR);
364 m_pBase->write8(0xff, NE_ISR);
365 m_pBase->write8(EnabledInterrupts, NE_IMR);
366 m_pBase->write8(CommandPage0Start, NE_CMD);
367 return true;
368}
369
370bool Ne2k::recoverReceiveOverflow(uint8_t irqStatus) {
371 const bool wasTransmitting = (m_pBase->read8(NE_CMD) & E8390_TRANS) != 0;
372
373 // National Semiconductor's overrun sequence requires the receiver to be
374 // stopped for at least one full frame time before its remote count is
375 // cleared. The reset-complete bit is explicitly not reliable here.
376 m_pBase->write8(CommandPage0Stop, NE_CMD);
377 if (!Time::delay(10 * Time::Multiplier::Millisecond)) {
378 return resetController();
379 }
380 m_pBase->write8(0x00, NE_RBCR0);
381 m_pBase->write8(0x00, NE_RBCR1);
382
383 const uint8_t completion =
384 (irqStatus | m_pBase->read8(NE_ISR)) & (InterruptTransmit | InterruptTransmitError);
385 const bool resend = wasTransmitting && !completion;
386
387 // Clear captured non-overrun causes before draining. A new receive during
388 // the drain then leaves RX set for the next bounded pass.
389 m_pBase->write8(irqStatus & ~InterruptOverflow, NE_ISR);
390 m_pBase->write8(completion, NE_ISR);
391 m_pBase->write8(E8390_TXOFF, NE_TCR);
392 m_pBase->write8(CommandPage0Start, NE_CMD);
393
394 if (!recv()) {
395 return resetController();
396 }
397
398 m_pBase->write8(InterruptOverflow, NE_ISR);
399 m_pBase->write8(E8390_TXCONFIG, NE_TCR);
400 if (resend) {
401 m_pBase->write8(CommandTransmit, NE_CMD);
402 }
403 return true;
404}
405
406void Ne2k::advanceReceiveBoundary(uint8_t nextPacket) {
407 m_NextPacket = nextPacket;
408 m_pBase->write8((m_NextPacket == PAGE_RX) ? (PAGE_STOP - 1) : (m_NextPacket - 1), NE_BNDRY);
409}
410
411bool Ne2k::recv() {
412 constexpr size_t RingPageCount = PAGE_STOP - PAGE_RX;
413
414 for (size_t packets = 0; packets < RingPageCount; ++packets) {
415 // Refresh CURR for every packet. A packet arriving after the IRQ was
416 // acknowledged must either be drained here or raise the source again.
417 m_pBase->write8(CommandPage1Start, NE_CMD);
418 const uint8_t current = m_pBase->read8(NE_CURR);
419 m_pBase->write8(CommandPage0Start, NE_CMD);
420 if (current < PAGE_RX || current >= PAGE_STOP) {
421 ERROR("NE2K: receive ring reported an invalid current page");
422 return false;
423 }
424 if (m_NextPacket == current) {
425 return true;
426 }
427
428 // Want status and length
429 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
430 m_pBase->write8(0, NE_RSAR0);
431 m_pBase->write8(m_NextPacket, NE_RSAR1);
432 m_pBase->write8(4, NE_RBCR0);
433 m_pBase->write8(0, NE_RBCR1);
434 m_pBase->write8(CommandRemoteRead, NE_CMD);
435
436 // Grab the information we want
437 const uint16_t status = m_pBase->read16(NE_DATA);
438 const uint16_t rawLength = m_pBase->read16(NE_DATA);
439 if (!waitForRemoteDma()) {
440 ERROR("NE2K: receive header DMA timed out");
441 return false;
442 }
443 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
444
445 const uint8_t nextPacket = status >> 8;
446 const bool nextInRing = nextPacket >= PAGE_RX && nextPacket < PAGE_STOP;
447 const bool validLength = rawLength >= 4 + MinimumPacketLength &&
448 (static_cast<size_t>(rawLength) - 4) <= MaximumPacketLength;
449 bool validNext = false;
450 if (nextInRing && validLength) {
451 // The 8390 header count excludes the four-byte ring header. Some
452 // clones round the next page one page higher, which is the only
453 // tolerated discrepancy.
454 size_t expected = m_NextPacket + 1 + (static_cast<size_t>(rawLength) >> 8);
455 while (expected >= PAGE_STOP) {
456 expected -= RingPageCount;
457 }
458 size_t roundedExpected = expected + 1;
459 if (roundedExpected >= PAGE_STOP) {
460 roundedExpected = PAGE_RX;
461 }
462 validNext = nextPacket == expected || nextPacket == roundedExpected;
463 }
464 const bool receiveOk = (status & InterruptReceive) != 0;
465 if (!validNext || !validLength || !receiveOk) {
466 WARNING("NE2K: dropping corrupt receive-ring entry (status="
467 << Hex << status << ", length=" << Dec << rawLength << Hex << ")");
468 // A valid next pointer preserves later packets. A corrupt pointer
469 // cannot be retried safely, so drop the visible ring contents.
470 advanceReceiveBoundary((validNext && validLength) ? nextPacket : current);
471 continue;
472 }
473
474 // The 8390 byte count includes the four-byte Ethernet CRC.
475 const uint16_t length = rawLength - 4;
476 // Remote byte count decrements by two in word mode. Round the hardware
477 // transfer up while keeping the packet handed to the stack exact.
478 const uint16_t dmaLength = (length + 1) & ~static_cast<uint16_t>(1);
479
480 // packet buffer
481 uint8_t* tmp = reinterpret_cast<uint8_t*>(NetworkStack::instance().getMemPool().allocateNow());
482 if (!tmp) {
483 advanceReceiveBoundary(nextPacket);
484 continue;
485 }
486 uint16_t* packBuffer = reinterpret_cast<uint16_t*>(tmp);
487 ByteSet(tmp, 0, length);
488
489 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
490 m_pBase->write8(4, NE_RSAR0);
491 m_pBase->write8(m_NextPacket, NE_RSAR1);
492 m_pBase->write8(dmaLength & 0xff, NE_RBCR0);
493 m_pBase->write8(dmaLength >> 8, NE_RBCR1);
494 m_pBase->write8(CommandRemoteRead, NE_CMD);
495
496 // read the packet
497 int i, words = length / 2, oddbytes = length % 2;
498 for (i = 0; i < words; ++i)
499 packBuffer[i] = m_pBase->read16(NE_DATA);
500 if (oddbytes) {
501 for (i = 0; i < oddbytes; ++i)
502 tmp[(length - oddbytes) + i] =
503 m_pBase->read16(NE_DATA) & 0xFF; // odd packet length handler
504 }
505
506 if (!waitForRemoteDma()) {
507 ERROR("NE2K: receive payload DMA timed out");
508 NetworkStack::instance().getMemPool().free(reinterpret_cast<uintptr_t>(tmp));
509 advanceReceiveBoundary(nextPacket);
510 return false;
511 }
512 m_pBase->write8(InterruptRemoteDmaComplete, NE_ISR);
513
514 advanceReceiveBoundary(nextPacket);
515
516 // push onto the queue
517 packet* p = new packet;
518 p->ptr = reinterpret_cast<uintptr_t>(packBuffer);
519 p->len = length;
520
521#ifdef NE2K_NO_THREADS
522
523 NetworkStack::instance().receive(p->len, p->ptr, this, 0);
524
526 delete p;
527
528#else
529
530 {
531 LockGuard<Spinlock> guard(m_PacketQueueLock);
532 m_PacketQueue.pushBack(p);
533 m_PacketQueueSize.release();
534 }
535
536#endif
537 }
538
539 WARNING("NE2K: receive ring drain exceeded its page budget");
540 return false;
541}
542
543int Ne2k::trampoline(void* p) {
544 Ne2k* pNe = reinterpret_cast<Ne2k*>(p);
545 pNe->receiveThread();
546 return 0;
547}
548
549void Ne2k::receiveThread() {
550 while (true) {
551 // handle the incoming packet
552 if (!m_PacketQueueSize.acquire()) {
553 if (Processor::information().getCurrentThread()->getUnwindState() != Thread::Continue) {
554 return;
555 }
556 continue;
557 }
558
559 // grab from the front
560 packet* p = 0;
561 {
562 LockGuard<Spinlock> guard(m_PacketQueueLock);
563 p = m_PacketQueue.popFront();
564 }
565
566 if (!p)
567 continue;
568 if (!p->ptr || !p->len) {
569 if (p->ptr) {
571 }
572 delete p;
573 continue;
574 }
575
576 // pass to the network stack
577 NetworkStack::instance().receive(p->len, p->ptr, this, 0);
578
579 // destroy the buffer now that it's handled
581 delete p;
582 }
583}
584
586 // free the old DNS servers list, if there is one
587 if (m_StationInfo.dnsServers)
588 delete[] m_StationInfo.dnsServers;
589
590 // MAC isn't changeable, so set it all manually
591 m_StationInfo.ipv4 = info.ipv4;
592 NOTICE("NE2K: Setting ipv4, " << info.ipv4.toString() << ", " << m_StationInfo.ipv4.toString()
593 << "...");
594
595 m_StationInfo.ipv6 = info.ipv6;
596 m_StationInfo.nIpv6Addresses = info.nIpv6Addresses;
597 NOTICE("NE2K: Copied " << info.nIpv6Addresses << " IPv6 addresses.");
598
599 m_StationInfo.subnetMask = info.subnetMask;
600 NOTICE("NE2K: Setting subnet mask, " << info.subnetMask.toString() << ", "
601 << m_StationInfo.subnetMask.toString() << "...");
602 m_StationInfo.gateway = info.gateway;
603 NOTICE("NE2K: Setting gateway, " << info.gateway.toString() << ", "
604 << m_StationInfo.gateway.toString() << "...");
605
606 // Callers do not free their dnsServers memory
607 m_StationInfo.dnsServers = info.dnsServers;
608 m_StationInfo.nDnsServers = info.nDnsServers;
609 NOTICE("NE2K: Setting DNS servers [" << Dec << m_StationInfo.nDnsServers << Hex
610 << " servers being set]...");
611
612 return true;
613}
614
616 return m_StationInfo;
617}
618
619IrqDisposition Ne2k::irq(irq_id_t number) {
620 constexpr size_t PassLimit = 8;
621 bool handled = false;
622 (void)number;
623
624 LockGuard<Mutex> dmaGuard(m_DmaLock);
625 if (m_Stopping) {
626 return IrqDisposition::NotHandled;
627 }
628 for (size_t pass = 0; pass < PassLimit; ++pass) {
629 const uint8_t irqStatus = m_pBase->read8(NE_ISR) & EnabledInterrupts;
630 if (!irqStatus) {
631 break;
632 }
633 handled = true;
634
635 if (irqStatus & InterruptOverflow) {
636 WARNING("NE2K: Receive buffer overflow");
637 if (!recoverReceiveOverflow(irqStatus)) {
638 ERROR("NE2K: receive overflow recovery failed");
639 }
640 continue;
641 }
642
643 // Acknowledge the captured bits before draining. If another packet
644 // arrives during the drain it sets RX again and the next pass owns it.
645 m_pBase->write8(irqStatus, NE_ISR);
646
647 if (irqStatus & (InterruptReceive | InterruptReceiveError)) {
648 if (!recv()) {
649 resetController();
650 }
651 }
652 if (irqStatus & InterruptTransmitError) {
653 WARNING("NE2K: Packet transmit failed!");
654 }
655 if (irqStatus & InterruptCounters) {
656 WARNING("NE2K: Counter overflow");
657 }
658 }
659
660 return handled ? IrqDisposition::Handled : IrqDisposition::NotHandled;
661}
662
664 // The NE2K chip doesn't support detecting the link state, so we have to
665 // just assume the link is active.
666 return true;
667}
virtual void setSpecificType(String str)
Definition Device.h:187
Vector< Address * > m_Addresses
Definition Device.h:349
Device * getParent() const
Definition Device.h:166
virtual uintptr_t getInterruptNumber()
Definition Device.h:271
virtual uint8_t read8(size_t offset=0)=0
virtual void write8(uint8_t value, size_t offset=0)=0
virtual void write16(uint16_t value, size_t offset=0)=0
virtual uint16_t read16(size_t offset=0)=0
virtual irq_id_t registerPciIrqHandler(IrqHandler *handler, Device *pDevice, const IrqPolicy &policy)=0
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
uintptr_t allocateNow()
Definition Ne2k.h:42
virtual const StationInfo & getStationInfo()
Definition Ne2k.cc:615
virtual bool send(size_t nBytes, uintptr_t buffer)
Definition Ne2k.cc:223
virtual IrqDisposition irq(irq_id_t number)
Definition Ne2k.cc:619
Ne2k(Network *pDev)
Definition Ne2k.cc:70
virtual bool setStationInfo(const StationInfo &info)
Definition Ne2k.cc:585
bool isConnected()
Definition Ne2k.cc:663
MemoryPool & getMemPool()
void deRegisterDevice(Network *pDevice)
static NetworkStack & instance()
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
void registerDevice(Network *pDevice)
static ProcessorInformation & information()
static void pause()
void release(size_t n=1)
Definition Semaphore.cc:549
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:355
size_t nDnsServers
Can contain IPv6 addresses.
Definition Network.h:51
IpAddress gateway
Automatically calculated?
Definition Network.h:47
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124
IrqDisposition
Definition IrqHandler.h:31