The Pedigree Project  0.1
3Com90x.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 
25 /*
26  * 3c90x.c -- This file implements the 3c90x driver for etherboot. Written
27  * by Greg Beeley, Greg.Beeley@LightSys.org. Modified by Steve Smith,
28  * Steve.Smith@Juno.Com. Alignment bug fix Neil Newell (nn@icenoir.net).
29  *
30  * This program Copyright (C) 1999 LightSys Technology Services, Inc.
31  * Portions Copyright (C) 1999 Steve Smith
32  *
33  * This program may be re-distributed in source or binary form, modified,
34  * sold, or copied for any purpose, provided that the above copyright message
35  * and this text are included with all source copies or derivative works, and
36  * provided that the above copyright message and this text are included in the
37  * documentation of any binary-only distributions. This program is distributed
38  * WITHOUT ANY WARRANTY, without even the warranty of FITNESS FOR A PARTICULAR
39  * PURPOSE or MERCHANTABILITY. Please read the associated documentation
40  * "3c90x.txt" before compiling and using this driver.
41  *
42  * --------
43  *
44  * Program written with the assistance of the 3com documentation for
45  * the 3c905B-TX card, as well as with some assistance from the 3c59x
46  * driver Donald Becker wrote for the Linux kernel, and with some assistance
47  * from the remainder of the Etherboot distribution.
48  *
49  * REVISION HISTORY:
50  *
51  * v0.10 1-26-1998 GRB Initial implementation.
52  * v0.90 1-27-1998 GRB System works.
53  * v1.00pre1 2-11-1998 GRB Got prom boot issue fixed.
54  * v2.0 9-24-1999 SCS Modified for 3c905 (from 3c905b code)
55  * Re-wrote poll and transmit for
56  * better error recovery and heavy
57  * network traffic operation
58  * v2.01 5-26-2993 NN Fixed driver alignment issue which
59  * caused system lockups if driver structures
60  * not 8-byte aligned.
61  *
62  */
63 
64 #include "3Com90x.h"
65 #include "3Com90xConstants.h"
66 #include "modules/system/network-stack/NetworkStack.h"
67 #include "pedigree/kernel/Log.h"
68 #include "pedigree/kernel/machine/Device.h"
69 #include "pedigree/kernel/machine/IrqManager.h"
70 #include "pedigree/kernel/machine/Machine.h"
71 #include "pedigree/kernel/machine/Network.h"
72 #include "pedigree/kernel/network/IpAddress.h"
73 #include "pedigree/kernel/network/MacAddress.h"
74 #include "pedigree/kernel/process/Thread.h"
75 #include "pedigree/kernel/processor/IoBase.h"
76 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
77 #include "pedigree/kernel/processor/Processor.h"
78 #include "pedigree/kernel/processor/ProcessorInformation.h"
79 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
80 #include "pedigree/kernel/utilities/Vector.h"
81 #include "pedigree/kernel/utilities/utility.h"
82 
83 int Nic3C90x::issueCommand(int cmd, int param)
84 {
85  uint32_t val;
86 
88  val = cmd;
89  val <<= 11;
90  val |= param;
91 
93  m_pBase->write16(val, regCommandIntStatus_w);
94 
96  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
97  ;
98 
99  return 0;
100 }
101 
102 int Nic3C90x::setWindow(int window)
103 {
105  if (m_CurrentWindow == window)
106  return 0;
107 
109  issueCommand(cmdSelectRegisterWindow, window);
110  m_CurrentWindow = window;
111 
112  return 0;
113 }
114 
115 uint16_t Nic3C90x::readEeprom(int address)
116 {
117  uint16_t val;
118 
120  setWindow(winEepromBios0);
121 
123  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
124  ;
125 
127  m_pBase->write16(address + (0x02 << 6), regEepromCommand_0_w);
128  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
129  ;
130  val = m_pBase->read16(regEepromData_0_w);
131 
132  return val;
133 }
134 
135 int Nic3C90x::writeEepromWord(int address, uint16_t value)
136 {
138  setWindow(winEepromBios0);
139 
141  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
142  ;
143 
145  m_pBase->write16(0x30, regEepromCommand_0_w);
146  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
147  ;
148 
150  m_pBase->write16(address + (0x03 << 6), regEepromCommand_0_w);
151  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
152  ;
153 
155  m_pBase->write16(value, regEepromData_0_w);
156  m_pBase->write16(0x30, regEepromCommand_0_w);
157  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
158  ;
159 
161  m_pBase->write16(address + (0x01 << 6), regEepromCommand_0_w);
162  while ((1 << 15) & m_pBase->read16(regEepromCommand_0_w))
163  ;
164 
165  return 0;
166 }
167 
168 int Nic3C90x::writeEeprom(int address, uint16_t value)
169 {
170  int cksum = 0, v;
171  int i;
172  int maxAddress, cksumAddress;
173 
174  if (m_isBrev)
175  {
176  maxAddress = 0x1f;
177  cksumAddress = 0x20;
178  }
179  else
180  {
181  maxAddress = 0x16;
182  cksumAddress = 0x17;
183  }
184 
186  if (writeEepromWord(address, value) == -1)
187  return -1;
188 
190  for (i = 0; i <= maxAddress; i++)
191  {
192  v = readEeprom(i);
193  cksum ^= (v & 0xff);
194  cksum ^= ((v >> 8) & 0xff);
195  }
196 
198  if (writeEepromWord(cksumAddress, cksum) == -1)
199  return -1;
200 
201  return 0;
202 }
203 
205 {
206 #ifdef CFG_3C90X_PRESERVE_XCVR
207  int cfg;
208 
210  setWindow(winTxRxOptions3);
211  cfg = m_pBase->read32(regInternalConfig_3_l);
212 #endif
213 
215  NOTICE("3C90x: Issuing RESET");
216  issueCommand(cmdGlobalReset, 0);
217 
219  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
220  ;
221 
225  setWindow(winAddressing2);
226  m_pBase->write16(0, regStationAddress_2_3w + 0);
227  m_pBase->write16(0, regStationAddress_2_3w + 2);
228  m_pBase->write16(0, regStationAddress_2_3w + 4);
229 
230 #ifdef CFG_3C90X_PRESERVE_XCVR
231 
232  setWindow(winTxRxOptions3);
233  m_pBase->write32(cfg, regInternalConfig_3_l);
234 
236  if ((cfg & 0x0300) == 0x0300)
237  issueCommand(cmdEnableDcConverter, 0);
238 #endif
239 
241  issueCommand(cmdTxReset, 0);
242  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
243  ;
244 
245  if (!m_isBrev)
246  m_pBase->write8(0x01, regTxFreeThresh_b);
247  issueCommand(cmdTxEnable, 0);
248 
252  if (m_isBrev)
253  issueCommand(cmdRxReset, 0x04);
254  else
255  issueCommand(cmdRxReset, 0x00);
256  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
257  ;
258 
259  issueCommand(cmdRxEnable, 0);
260 
262  issueCommand(cmdSetInterruptEnable, ENABLED_INTS);
263  issueCommand(cmdSetIndicationEnable, ENABLED_INTS); // 0x0014);
264  issueCommand(cmdAcknowledgeInterrupt, 0xff); // 0x661);
265 }
266 
267 bool Nic3C90x::send(size_t nBytes, uintptr_t buffer)
268 {
270  issueCommand(cmdStallCtl, 2);
271 
273  m_pBase->read16(regCommandIntStatus_w);
274  m_pBase->read16(regCommandIntStatus_w);
275  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
276  ;
277 
278  physical_uintptr_t destPtr = m_pTxBuffPhys;
279  size_t dud = 0;
280  if (Processor::information().getVirtualAddressSpace().isMapped(
281  reinterpret_cast<void *>(buffer)))
282  {
283  Processor::information().getVirtualAddressSpace().getMapping(
284  reinterpret_cast<void *>(buffer), destPtr, dud);
285  destPtr += buffer & 0xFFF;
286  }
287  else
288  MemoryCopy(m_pTxBuffVirt, reinterpret_cast<void *>(buffer), nBytes);
289 
291  m_TransmitDPD->DnNextPtr = 0;
292 
294  m_TransmitDPD->FrameStartHeader = nBytes | 0x8000;
295  // m_TransmitDPD->HdrAddr = m_pTxBuffPhys;
296  // m_TransmitDPD->HdrLength = Ethernet::instance().ethHeaderSize();
297  m_TransmitDPD->DataAddr = static_cast<uint32_t>(
298  destPtr); // m_pTxBuffPhys; // + m_TransmitDPD->HdrLength;
299  m_TransmitDPD->DataLength =
300  (nBytes /* - m_TransmitDPD->HdrLength */) + (1U << 31U);
301 
303  m_pBase->write32(m_pDPD, regDnListPtr_l);
304 
306  issueCommand(cmdStallCtl, 3);
307  while (m_pBase->read32(regDnListPtr_l) != 0)
308  ;
309 
310  m_TxMutex.acquire();
311 
312  return true;
313 }
314 
316  : Network(pDev), m_pBase(0), m_isBrev(0), m_CurrentWindow(0),
317  m_pRxBuffVirt(0), m_pTxBuffVirt(0), m_pRxBuffPhys(0), m_pTxBuffPhys(0),
318  m_RxBuffMR("3c90x-rxbuffer"), m_TxBuffMR("3c90x-txbuffer"), m_pDPD(0),
319  m_DPDMR("3c90x-dpd"), m_pUPD(0), m_UPDMR("3c90x-upd"), m_TransmitDPD(0),
320  m_ReceiveUPD(0), m_RxMutex(0), m_TxMutex(0), m_PendingPackets()
321 {
322  setSpecificType(String("3c90x-card"));
323 
324  int i, c;
325  uint16_t eeprom[0x21];
326  uint32_t cfg;
327  uint32_t mopt;
328  uint32_t mstat;
329  uint16_t linktype;
330 #define HWADDR_OFFSET 10
331 
332  // allocate the rx and tx buffers
333  if (!PhysicalMemoryManager::instance().allocateRegion(
334  m_RxBuffMR, (MAX_PACKET_SIZE / 0x1000) + 1,
336  {
337  ERROR("3C90x: Couldn't allocate Rx Buffer!");
338  return;
339  }
340  if (!PhysicalMemoryManager::instance().allocateRegion(
341  m_TxBuffMR, (MAX_PACKET_SIZE / 0x1000) + 1,
343  {
344  ERROR("3C90x: Couldn't allocate Tx Buffer!");
345  return;
346  }
347  m_pRxBuffVirt = static_cast<uint8_t *>(m_RxBuffMR.virtualAddress());
348  m_pTxBuffVirt = static_cast<uint8_t *>(m_TxBuffMR.virtualAddress());
349  m_pRxBuffPhys = m_RxBuffMR.physicalAddress();
350  m_pTxBuffPhys = m_TxBuffMR.physicalAddress();
351 
352  if (!PhysicalMemoryManager::instance().allocateRegion(
355  {
356  ERROR("3C90x: Couldn't allocated buffer for DPD\n");
357  return;
358  }
359  if (!PhysicalMemoryManager::instance().allocateRegion(
362  {
363  ERROR("3C90x: Couldn't allocated buffer for UPD\n");
364  return;
365  }
366  m_pDPD = m_DPDMR.physicalAddress();
367  m_pUPD = m_UPDMR.physicalAddress();
368  m_TransmitDPD = reinterpret_cast<TXD *>(m_DPDMR.virtualAddress());
369  m_ReceiveUPD = reinterpret_cast<RXD *>(m_UPDMR.virtualAddress());
370 
371  // configure the UPD... turn it into a list with a well-defined beginning
372  // and end
373  for (size_t iUpd = 0; iUpd < NUM_UPDS; iUpd++)
374  {
375  if ((iUpd + 1) == NUM_UPDS)
376  m_ReceiveUPD[iUpd].UpNextPtr = 0;
377  else
378  m_ReceiveUPD[iUpd].UpNextPtr = m_pUPD + ((iUpd + 1) * sizeof(RXD));
379  m_ReceiveUPD[iUpd].UpPktStatus = 0;
380  m_ReceiveUPD[iUpd].DataAddr = m_pRxBuffPhys + (iUpd * 1536);
381  m_ReceiveUPD[iUpd].DataLength = 1536 + (1U << 31U);
382  }
383 
384  // grab the IO ports
385  m_pBase = m_Addresses[0]->m_Io;
386 
387  m_CurrentWindow = 255;
388 
389  reset();
390 
391  switch (readEeprom(0x03))
392  {
393  case 0x9000:
394  case 0x9001:
395  case 0x9050:
396  case 0x9051:
397  m_isBrev = 0;
398  break;
399 
400  case 0x9004:
401  case 0x9005:
402  case 0x9006:
403  case 0x900A:
404  case 0x9055:
405  case 0x9056:
406  case 0x905A:
407  default:
408  m_isBrev = 1;
409  break;
410  }
411 
413  if (m_isBrev)
414  {
415  for (i = 0; i < 0x20; i++)
416  eeprom[i] = readEeprom(i);
417 
418 #ifdef CFG_3C90X_BOOTROM_FIX
419 
420  /* only necessary for 3c905b revision cards with boot PROM bug!!! */
421  writeEeprom(0x13, 0x0160);
422 #endif
423 
424 #ifdef CFG_3C90X_XCVR
425 
426  if (CFG_3C90X_XCVR == 255)
427  writeEeprom(0x16, 0);
428 
432  else
433  writeEeprom(0x16, XCVR_MAGIC + ((CFG_3C90X_XCVR) &0x000F));
434 #endif
435  }
436  else
437  {
438  for (i = 0; i < 0x17; i++)
439  eeprom[i] = readEeprom(i);
440  }
441 
443  m_StationInfo.mac.setMac(eeprom, true);
444  NOTICE(
445  "3C90x MAC: " << m_StationInfo.mac[0] << ":" << m_StationInfo.mac[1]
446  << ":" << m_StationInfo.mac[2] << ":"
447  << m_StationInfo.mac[3] << ":" << m_StationInfo.mac[4]
448  << ":" << m_StationInfo.mac[5] << ".");
449 
450  /* Test if the link is good, if so continue */
451  setWindow(winDiagnostics4);
452  mstat = m_pBase->read16(regMediaStatus_4_w);
453  if ((mstat & (1 << 11)) == 0)
454  {
455  ERROR("3C90x: Valid link not established");
456  return;
457  }
458 
460  setWindow(winAddressing2);
461  m_pBase->write16(
462  HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 0]), regStationAddress_2_3w);
463  m_pBase->write16(
464  HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 1]), regStationAddress_2_3w + 2);
465  m_pBase->write16(
466  HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 2]), regStationAddress_2_3w + 4);
467  m_pBase->write16(0, regStationMask_2_3w);
468  m_pBase->write16(0, regStationMask_2_3w + 2);
469  m_pBase->write16(0, regStationMask_2_3w + 4);
470 
477  setWindow(winTxRxOptions3);
478  mopt = m_pBase->read16(regResetMediaOptions_3_w);
479 
481  if (!m_isBrev)
482  mopt &= 0x7f;
483 
484  NOTICE("3C90x connectors present:");
485  c = 0;
486  linktype = 0x0008;
487  if (mopt & 0x01)
488  {
489  NOTICE(((c++) ? ", " : "") << "100BASE-T4");
490  linktype = 0x0006;
491  }
492  if (mopt & 0x04)
493  {
494  NOTICE(((c++) ? ", " : "") << "100BASE-FX");
495  linktype = 0x0005;
496  }
497  if (mopt & 0x10)
498  {
499  NOTICE(((c++) ? ", " : "") << "10BASE2");
500  linktype = 0x0003;
501  }
502  if (mopt & 0x20)
503  {
504  NOTICE(((c++) ? ", " : "") << "AUI");
505  linktype = 0x0001;
506  }
507  if (mopt & 0x40)
508  {
509  NOTICE(((c++) ? ", " : "") << "MII");
510  linktype = 0x0006;
511  }
512  if ((mopt & 0xA) == 0xA)
513  {
514  NOTICE(((c++) ? ", " : "") << "10BASE-T / 100BASE-TX");
515  linktype = 0x0008;
516  }
517  else if ((mopt & 0xa) == 0x2)
518  {
519  NOTICE(((c++) ? ", " : "") << "100BASE-TX");
520  linktype = 0x0008;
521  }
522  else if ((mopt & 0xa) == 0x8)
523  {
524  NOTICE(((c++) ? ", " : "") << "10BASE-T");
525  linktype = 0x0008;
526  }
527 
531  if (m_isBrev)
532  {
533  if ((eeprom[0x16] & 0xff00) == XCVR_MAGIC)
534  linktype = eeprom[0x16] & 0x000f;
535  }
536  else
537  {
538 #ifdef CFG_3C90X_XCVR
539  if (CFG_3C90X_XCVR != 255)
540  linktype = CFG_3C90X_XCVR;
541 #endif
542 
543  if (linktype == 0x0009)
544  {
545  if (m_isBrev)
546  WARNING("3C90x: MII External MAC mode only supported on "
547  "B-revision cards! Falling back to MII mode.");
548  linktype = 0x0006;
549  }
550  }
551 
553  if (linktype == 0x0003)
554  issueCommand(cmdEnableDcConverter, 0);
555 
557  setWindow(winTxRxOptions3);
558  cfg = m_pBase->read32(regInternalConfig_3_l);
559  cfg &= ~(0xF << 20);
560  cfg |= (linktype << 20);
561  m_pBase->write32(cfg, regInternalConfig_3_l);
562 
564  issueCommand(cmdTxReset, 0);
565  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
566  ;
567 
568  if (!m_isBrev)
569  m_pBase->write8(0x01, regTxFreeThresh_b);
570  issueCommand(cmdTxEnable, 0);
571 
575  if (m_isBrev)
576  issueCommand(cmdRxReset, 0x04);
577  else
578  issueCommand(cmdRxReset, 0x00);
579  while (m_pBase->read16(regCommandIntStatus_w) & INT_CMDINPROGRESS)
580  ;
581 
584  issueCommand(cmdSetRxFilter, 0x01 + 0x02 + 0x04);
585  issueCommand(cmdRxEnable, 0);
586 
588  issueCommand(cmdSetInterruptEnable, ENABLED_INTS);
589  issueCommand(cmdSetIndicationEnable, ENABLED_INTS); // 0x0014);
590  issueCommand(cmdAcknowledgeInterrupt, 0xff); // 0x661);
591 
592  // Set the location for the UPD
593  m_pBase->write32(m_pUPD, regUpListPtr_l);
594 
595 // register the packet queue handler
596 #ifdef THREADS
597  Thread *pThread = new Thread(
598  Processor::information().getCurrentThread()->getParent(), &trampoline,
599  reinterpret_cast<void *>(this));
600  pThread->detach();
601 #endif
602 
603  // install the IRQ
604  Machine::instance().getIrqManager()->registerIsaIrqHandler(
605  getInterruptNumber(), static_cast<IrqHandler *>(this));
607 }
608 
609 Nic3C90x::~Nic3C90x()
610 {
611 }
612 
613 int Nic3C90x::trampoline(void *p)
614 {
615  Nic3C90x *pNic = reinterpret_cast<Nic3C90x *>(p);
616  pNic->receiveThread();
617  return 0;
618 }
619 
620 void Nic3C90x::receiveThread()
621 {
622  while (true)
623  {
624  m_RxMutex.acquire();
625 
626  // When we come here, the UpListPtr register will hold the *next* UPD...
627  // What we want is the one that it used! That's ok, it's not difficult
628  // to find that out...
629  // However, if the next is zero, the IRQ notified us of the *last* UPD
630  // in the list. That needs to be handled properly too.
631  uintptr_t currUpdPhys =
632  reinterpret_cast<uintptr_t>(m_PendingPackets.popFront());
633  uintptr_t myNum;
634  if (currUpdPhys != 0)
635  {
636  uintptr_t myOffset = (currUpdPhys - m_pUPD);
637  myNum = (myOffset / sizeof(RXD)) - 1;
638  }
639  else
640  myNum = NUM_UPDS - 1;
641  RXD *usedUpd = &m_ReceiveUPD[myNum];
642 
643  if (usedUpd->UpPktStatus & (1 << 14))
644  {
645  // an error occurred
646  ERROR(
647  "3C90x: error, UpPktStatus = " << usedUpd->UpPktStatus << ".");
648  return;
649  }
650 
651  size_t packLen = usedUpd->UpPktStatus & 0x1FFF;
652 
654  packLen,
655  reinterpret_cast<uintptr_t>(m_pRxBuffVirt + (myNum * 1536)), this,
656  0);
657 
658  // reset the UPD's status so it can be used again
659  usedUpd->UpPktStatus = 0;
660 
661  // Reset the location for the UPD, if we're stalling
662  if (currUpdPhys == 0)
663  m_pBase->write32(m_pUPD, regUpListPtr_l);
664  }
665 }
666 
667 bool Nic3C90x::irq(irq_id_t number, InterruptState &state)
668 {
669  // disable interrupts
670  issueCommand(cmdSetInterruptEnable, 0);
671 
672  while (1)
673  {
674  uint16_t status = m_pBase->read16(regCommandIntStatus_w);
675 
676  // check that one of the enabled IRQs is triggered
677  if ((status & ENABLED_INTS) == 0)
678  break;
679 
680  // acknowledge the interrupts
681  issueCommand(cmdAcknowledgeInterrupt, (status & ENABLED_INTS));
682 
683  // handle...
684  if (status & INT_UPCOMPLETE)
685  {
686  void *currPhys =
687  reinterpret_cast<void *>(m_pBase->read32(regUpListPtr_l));
688  m_PendingPackets.pushBack(currPhys);
689  m_RxMutex.release();
690  }
691 
692  if (status & INT_TXCOMPLETE)
693  {
694  m_TxMutex.release();
695 
696  uint8_t txStatus = m_pBase->read8(regTxStatus_b);
697 
698  // ack it
699  m_pBase->write8(0, regTxStatus_b);
700 
701  if ((txStatus & 0xbf) == 0x80)
702  continue;
703 
704  if (txStatus & 0x02)
705  {
706  ERROR("3C90x: TX Reclaim Error");
707  reset();
708  }
709  else if (txStatus & 0x04)
710  {
711  ERROR("3C90x: TX Status Overflow");
712  for (int i = 0; i < 32; i++)
713  m_pBase->write8(0, regTxStatus_b);
714  issueCommand(cmdTxEnable, 0);
715  }
716  else if (txStatus & 0x08)
717  {
718  ERROR("3C90x: TX Max Collisions");
719  issueCommand(cmdTxEnable, 0);
720  }
721  else if (txStatus & 0x10)
722  {
723  ERROR("3C90x: TX Underrun");
724  reset();
725  }
726  else if (txStatus & 0x20)
727  {
728  ERROR("3C90x: TX Jabber");
729  reset();
730  }
731  else if ((txStatus & 0x80) != 0x80)
732  {
733  ERROR("3C90x: Internal Error - Incomplete Transmission");
734  reset();
735  }
736  }
737 
738  if (status & INT_HOSTERROR)
739  {
740  NOTICE("Host error IRQ");
741  reset();
742  }
743 
744  if (status & INT_UPDATESTATS)
745  NOTICE("UpdateStats IRQ");
746  }
747 
748  // Re-enable interrupts
749  issueCommand(cmdSetInterruptEnable, ENABLED_INTS);
750 
751  /*
752  XL_SEL_WIN(7);
753 
754  if (ifp->if_snd.ifq_head != NULL)
755  xl_start(ifp);
756  */
757 
758  return true;
759 }
760 
762 {
763  // free the old DNS servers list, if there is one
764  if (m_StationInfo.dnsServers)
765  delete[] m_StationInfo.dnsServers;
766 
767  // MAC isn't changeable, so set it all manually
768  m_StationInfo.ipv4 = info.ipv4;
769  NOTICE(
770  "3C90x: Setting ipv4, " << info.ipv4.toString() << ", "
771  << m_StationInfo.ipv4.toString() << "...");
772  m_StationInfo.ipv6 = info.ipv6;
773 
774  m_StationInfo.subnetMask = info.subnetMask;
775  NOTICE(
776  "3C90x: Setting subnet mask, " << info.subnetMask.toString() << ", "
777  << m_StationInfo.subnetMask.toString()
778  << "...");
779  m_StationInfo.gateway = info.gateway;
780  NOTICE(
781  "3C90x: Setting gateway, " << info.gateway.toString() << ", "
782  << m_StationInfo.gateway.toString()
783  << "...");
784 
785  // Callers do not free their dnsServers memory
786  m_StationInfo.dnsServers = info.dnsServers;
787  m_StationInfo.nDnsServers = info.nDnsServers;
788  NOTICE(
789  "3C90x: Setting DNS servers [" << Dec << m_StationInfo.nDnsServers
790  << Hex << " servers being set]...");
791 
792  return true;
793 }
794 
796 {
797  return m_StationInfo;
798 }
virtual bool irq(irq_id_t number, InterruptState &state)
Definition: 3Com90x.cc:667
int setWindow(int window)
Definition: 3Com90x.cc:102
void pushBack(const T &value)
Definition: List.h:232
static PhysicalMemoryManager & instance()
Definition: cmd.h:30
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition: Semaphore.h:62
int issueCommand(int cmd, int param)
Definition: 3Com90x.cc:83
virtual void write8(uint8_t value, size_t offset=0)=0
void reset()
Definition: 3Com90x.cc:204
T popFront()
Definition: List.h:319
uint8_t m_isBrev
Definition: 3Com90x.h:75
virtual uint16_t read16(size_t offset=0)=0
Definition: String.h:49
IpAddress gateway
Automatically calculated?
virtual const StationInfo & getStationInfo()
Definition: 3Com90x.cc:795
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual uintptr_t getInterruptNumber()
Definition: Device.h:262
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
size_t nDnsServers
Can contain IPv6 addresses.
virtual void write16(uint16_t value, size_t offset=0)=0
#define WARNING(text)
Definition: Log.h:78
Nic3C90x(Network *pDev)
Definition: 3Com90x.cc:315
virtual void setSpecificType(String str)
Definition: Device.h:174
void release(size_t n=1)
Definition: Semaphore.cc:239
virtual uint32_t read32(size_t offset=0)=0
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
uint16_t readEeprom(int address)
Definition: 3Com90x.cc:115
physical_uintptr_t physicalAddress() const
Definition: MemoryRegion.cc:44
int writeEeprom(int address, uint16_t value)
Definition: 3Com90x.cc:168
int writeEepromWord(int address, uint16_t value)
Definition: 3Com90x.cc:135
static NetworkStack & instance()
Definition: NetworkStack.h:47
void registerDevice(Network *pDevice)
virtual bool send(size_t nBytes, uintptr_t buffer)
Definition: 3Com90x.cc:267
Vector< Address * > m_Addresses
Definition: Device.h:362
Definition: Thread.h:54
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, bool bEdge=false)=0
virtual uint8_t read8(size_t offset=0)=0
virtual bool setStationInfo(const StationInfo &info)
Definition: 3Com90x.cc:761
void * virtualAddress() const
Definition: MemoryRegion.cc:39
#define ERROR(text)
Definition: Log.h:82
bool detach()
Definition: Thread.cc:885
Definition: Log.h:138
virtual void write32(uint32_t value, size_t offset=0)=0
Device * getParent() const
Definition: Device.h:149