182 if (!waitForEepromReady())
186 m_pBase->
write16(0x30, regEepromCommand_0_w);
187 if (!waitForEepromReady())
191 m_pBase->
write16(address + (0x03 << 6), regEepromCommand_0_w);
192 if (!waitForEepromReady())
196 m_pBase->
write16(value, regEepromData_0_w);
197 m_pBase->
write16(0x30, regEepromCommand_0_w);
198 if (!waitForEepromReady())
202 m_pBase->
write16(address + (0x01 << 6), regEepromCommand_0_w);
203 if (!waitForEepromReady())
243#ifdef CFG_3C90X_PRESERVE_XCVR
249 cfg = m_pBase->
read32(regInternalConfig_3_l);
253 NOTICE(
"3C90x: Issuing RESET");
265 m_pBase->
write16(0, regStationAddress_2_3w + 0);
266 m_pBase->
write16(0, regStationAddress_2_3w + 2);
267 m_pBase->
write16(0, regStationAddress_2_3w + 4);
269#ifdef CFG_3C90X_PRESERVE_XCVR
273 m_pBase->
write32(cfg, regInternalConfig_3_l);
276 if ((cfg & 0x0300) == 0x0300)
286 m_pBase->
write8(0x01, regTxFreeThresh_b);
348 if (!buffer || !nBytes || nBytes > UpPacketLengthMask) {
349 ERROR(
"3C90x: invalid transmit packet length " <<
Dec << nBytes <<
Hex);
357 if (!m_Active || m_Stopping)
362 if (!stopDeviceLocked())
363 FATAL(
"3C90x could not halt DMA after a command timeout.");
371 (void)discardedCompletions;
372 m_TxSuccessful =
false;
377 MemoryCopy(m_pTxBuffVirt,
reinterpret_cast<void*
>(buffer), nBytes);
378 const physical_uintptr_t destPtr = m_pTxBuffPhys;
381 m_TransmitDPD->DnNextPtr = 0;
384 m_TransmitDPD->FrameStartHeader = nBytes | 0x8000;
387 m_TransmitDPD->DataAddr =
388 static_cast<uint32_t
>(destPtr);
389 m_TransmitDPD->DataLength = (nBytes ) + (1U << 31U);
393 m_pBase->
write32(m_pDPD, regDnListPtr_l);
397 if (!stopDeviceLocked())
398 FATAL(
"3C90x could not halt DMA after a command timeout.");
402 bool downloadComplete =
false;
403 for (
size_t poll = 0; poll < DownloadPollLimit; ++poll) {
404 if (!m_pBase->
read32(regDnListPtr_l)) {
405 downloadComplete =
true;
409 if (!Time::delay(Time::Multiplier::Millisecond))
412 if (!downloadComplete) {
413 ERROR(
"3C90x: packet download timed out");
414 if (!stopDeviceLocked())
415 FATAL(
"3C90x could not halt DMA after a download timeout.");
424 if (m_Active && !m_Stopping && !stopDeviceLocked())
425 FATAL(
"3C90x could not halt DMA after a transmit timeout.");
430 return m_Active && !m_Stopping && m_TxSuccessful;
442 m_RxBuffMR(
"3c90x-rxbuffer"),
443 m_TxBuffMR(
"3c90x-txbuffer"),
445 m_DPDMR(
"3c90x-dpd"),
447 m_UPDMR(
"3c90x-upd"),
453 m_RxConsumerIndex(0),
457 m_TxSuccessful(false),
458 m_Initialised(false) {
462 uint16_t eeprom[0x21];
467#define HWADDR_OFFSET 10
470 const size_t packetBufferPages = DriverDma::pageCountForBytes(MAX_PACKET_SIZE);
473 ERROR(
"3C90x: Couldn't allocate Rx Buffer!");
478 ERROR(
"3C90x: Couldn't allocate Tx Buffer!");
481 m_pRxBuffVirt =
static_cast<uint8_t*
>(m_RxBuffMR.
virtualAddress());
482 m_pTxBuffVirt =
static_cast<uint8_t*
>(m_TxBuffMR.
virtualAddress());
488 ERROR(
"3C90x: Couldn't allocated buffer for DPD\n");
493 ERROR(
"3C90x: Couldn't allocated buffer for UPD\n");
503 for (
size_t iUpd = 0; iUpd < NUM_UPDS; iUpd++) {
504 if ((iUpd + 1) == NUM_UPDS)
505 m_ReceiveUPD[iUpd].UpNextPtr = 0;
507 m_ReceiveUPD[iUpd].UpNextPtr = m_pUPD + ((iUpd + 1) *
sizeof(
RXD));
508 m_ReceiveUPD[iUpd].UpPktStatus = 0;
509 m_ReceiveUPD[iUpd].DataAddr = m_pRxBuffPhys + (iUpd * 1536);
510 m_ReceiveUPD[iUpd].DataLength = 1536 + (1U << 31U);
516 m_CurrentWindow = 255;
519 ERROR(
"3C90x: controller reset timed out");
523 uint16_t productId = 0;
525 ERROR(
"3C90x: failed to read product ID from EEPROM");
551 for (i = 0; i < 0x20; i++) {
553 ERROR(
"3C90x: failed to load EEPROM contents");
558#ifdef CFG_3C90X_BOOTROM_FIX
567 if (CFG_3C90X_XCVR == 255) {
576 if (
writeEeprom(0x16, XCVR_MAGIC + ((CFG_3C90X_XCVR) & 0x000F)) < 0)
581 for (i = 0; i < 0x17; i++) {
583 ERROR(
"3C90x: failed to load EEPROM contents");
590 m_StationInfo.mac.setMac(eeprom,
true);
591 NOTICE(
"3C90x MAC: " << m_StationInfo.mac[0] <<
":" << m_StationInfo.mac[1] <<
":"
592 << m_StationInfo.mac[2] <<
":" << m_StationInfo.mac[3] <<
":"
593 << m_StationInfo.mac[4] <<
":" << m_StationInfo.mac[5] <<
".");
598 mstat = m_pBase->
read16(regMediaStatus_4_w);
599 if ((mstat & (1 << 11)) == 0) {
600 ERROR(
"3C90x: Valid link not established");
607 m_pBase->
write16(HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 0]), regStationAddress_2_3w);
608 m_pBase->
write16(HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 1]), regStationAddress_2_3w + 2);
609 m_pBase->
write16(HOST_TO_BIG16(eeprom[HWADDR_OFFSET + 2]), regStationAddress_2_3w + 4);
610 m_pBase->
write16(0, regStationMask_2_3w);
611 m_pBase->
write16(0, regStationMask_2_3w + 2);
612 m_pBase->
write16(0, regStationMask_2_3w + 4);
622 mopt = m_pBase->
read16(regResetMediaOptions_3_w);
628 NOTICE(
"3C90x connectors present:");
632 NOTICE(((c++) ?
", " :
"") <<
"100BASE-T4");
636 NOTICE(((c++) ?
", " :
"") <<
"100BASE-FX");
640 NOTICE(((c++) ?
", " :
"") <<
"10BASE2");
644 NOTICE(((c++) ?
", " :
"") <<
"AUI");
648 NOTICE(((c++) ?
", " :
"") <<
"MII");
651 if ((mopt & 0xA) == 0xA) {
652 NOTICE(((c++) ?
", " :
"") <<
"10BASE-T / 100BASE-TX");
654 }
else if ((mopt & 0xa) == 0x2) {
655 NOTICE(((c++) ?
", " :
"") <<
"100BASE-TX");
657 }
else if ((mopt & 0xa) == 0x8) {
658 NOTICE(((c++) ?
", " :
"") <<
"10BASE-T");
666 if ((eeprom[0x16] & 0xff00) == XCVR_MAGIC)
667 linktype = eeprom[0x16] & 0x000f;
670 if (CFG_3C90X_XCVR != 255)
671 linktype = CFG_3C90X_XCVR;
674 if (linktype == 0x0009) {
677 "3C90x: MII External MAC mode only supported on "
678 "B-revision cards! Falling back to MII mode.");
684 if (linktype == 0x0003 && !
issueCommand(cmdEnableDcConverter, 0))
690 cfg = m_pBase->
read32(regInternalConfig_3_l);
692 cfg |= (linktype << 20);
693 m_pBase->
write32(cfg, regInternalConfig_3_l);
700 m_pBase->
write8(0x01, regTxFreeThresh_b);
730 m_pBase->
write32(m_pUPD, regUpListPtr_l);
734 static_cast<IrqHandler*
>(
this),
this, IrqPolicy::pciIntxThreaded());
736 ERROR(
"3C90x: could not register its PCI interrupt");
738 FATAL(
"3C90x could not halt DMA after IRQ registration failed.");
744 bool enabled =
false;
748 enabled =
issueCommand(cmdSetInterruptEnable, ENABLED_INTS);
750 m_Initialised =
true;
751 else if (!stopDeviceLocked())
752 FATAL(
"3C90x could not halt DMA after interrupt enable failed.");
756 if (!Machine::instance().getIrqManager()->unregisterHandler(m_IrqId,
this)) {
757 FATAL(
"3C90x could not unregister a failed IRQ callback.");
787 struct ReceivedPacket {
792 constexpr size_t PassLimit = 16;
793 ReceivedPacket receivedPackets[NUM_UPDS] = {};
794 size_t receivedPacketCount = 0;
795 bool handled =
false;
803 return IrqDisposition::NotHandled;
805 uint16_t status = m_pBase->
read16(regCommandIntStatus_w);
806 if ((status & ENABLED_INTS) == 0)
807 return IrqDisposition::NotHandled;
813 if (!stopDeviceLocked())
814 FATAL(
"3C90x could not quiesce after IRQ gating failed.");
815 return IrqDisposition::Handled;
818 for (
size_t pass = 0; pass < PassLimit; ++pass) {
819 status = m_pBase->
read16(regCommandIntStatus_w);
822 if ((status & ENABLED_INTS) == 0)
829 if (!
issueCommand(cmdAcknowledgeInterrupt, (status & ENABLED_INTS))) {
830 if (!stopDeviceLocked())
831 FATAL(
"3C90x could not quiesce after IRQ ACK failed.");
835 bool receiveBatch =
false;
836 if (status & INT_UPCOMPLETE) {
838 bool wrapped =
false;
839 for (
size_t scanned = 0; scanned < NUM_UPDS; ++scanned) {
840 RXD& usedUpd = m_ReceiveUPD[m_RxConsumerIndex];
841 const uint32_t packetStatus = usedUpd.UpPktStatus;
842 if (!(packetStatus & UpPacketComplete))
846 const size_t packetLength = packetStatus & UpPacketLengthMask;
847 if (packetStatus & UpPacketError) {
848 ERROR(
"3C90x: receive error, UpPktStatus = " << packetStatus <<
".");
849 }
else if (!packetLength || packetLength > ReceiveSlotSize) {
850 ERROR(
"3C90x: invalid received packet length " << packetLength);
852 uint8_t* packet = m_ReceiveStaging + (receivedPacketCount * ReceiveSlotSize);
853 MemoryCopy(packet, m_pRxBuffVirt + (m_RxConsumerIndex * ReceiveSlotSize), packetLength);
854 receivedPackets[receivedPacketCount++] = {packet, packetLength};
857 usedUpd.UpPktStatus = 0;
859 if (m_RxConsumerIndex == NUM_UPDS) {
860 m_RxConsumerIndex = 0;
867 const bool uploadStalled =
issueCommand(cmdStallCtl, 0);
870 m_pBase->
write32(m_pUPD, regUpListPtr_l);
873 if (!stopDeviceLocked()) {
875 "3C90x could not halt DMA after receive-list "
882 if (status & INT_HOSTERROR) {
883 ERROR(
"3C90x: host error IRQ");
884 if (!stopDeviceLocked())
885 FATAL(
"3C90x could not halt DMA after a host error.");
886 }
else if (status & INT_TXCOMPLETE) {
887 const uint8_t txStatus = m_pBase->
read8(regTxStatus_b);
891 m_pBase->
write8(0, regTxStatus_b);
892 m_TxSuccessful = (txStatus & 0xbf) == 0x80;
894 if (!m_TxSuccessful) {
896 ERROR(
"3C90x: TX Reclaim Error");
897 else if (txStatus & 0x04)
898 ERROR(
"3C90x: TX Status Overflow");
899 else if (txStatus & 0x08)
900 ERROR(
"3C90x: TX Max Collisions");
901 else if (txStatus & 0x10)
902 ERROR(
"3C90x: TX Underrun");
903 else if (txStatus & 0x20)
904 ERROR(
"3C90x: TX Jabber");
907 "3C90x: Internal Error - Incomplete "
910 if (!stopDeviceLocked()) {
912 "3C90x could not halt DMA after a transmit "
920 if (m_Stopping || receiveBatch)
926 if (m_Active && !m_Stopping && !
issueCommand(cmdSetInterruptEnable, ENABLED_INTS)) {
927 if (!stopDeviceLocked())
928 FATAL(
"3C90x could not quiesce after IRQ rearm failed.");
932 for (
size_t i = 0; i < receivedPacketCount; ++i) {
934 reinterpret_cast<uintptr_t
>(receivedPackets[i].data),
this, 0);
944 return handled ? IrqDisposition::Handled : IrqDisposition::NotHandled;
949 if (m_StationInfo.dnsServers)
950 delete[] m_StationInfo.dnsServers;
953 m_StationInfo.ipv4 = info.ipv4;
954 NOTICE(
"3C90x: Setting ipv4, " << info.ipv4.toString() <<
", " << m_StationInfo.ipv4.toString()
956 m_StationInfo.ipv6 = info.ipv6;
958 m_StationInfo.subnetMask = info.subnetMask;
959 NOTICE(
"3C90x: Setting subnet mask, " << info.subnetMask.toString() <<
", "
960 << m_StationInfo.subnetMask.toString() <<
"...");
961 m_StationInfo.
gateway = info.gateway;
962 NOTICE(
"3C90x: Setting gateway, " << info.gateway.toString() <<
", "
963 << m_StationInfo.
gateway.toString() <<
"...");
966 m_StationInfo.dnsServers = info.dnsServers;
969 <<
" servers being set]...");