⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_3c509.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 4 页
字号:
  }  bool haveRoom = (txFree >= inv.entry.len);    if (haveRoom) {    /* Send the packet length:  ?? why not out32 ?? */    out16(inv.entry.len, ni->ioAddr + Wn1TxFifo);    out16(0x0, ni->ioAddr + Wn1TxFifo);    IoWrPkt(ni, inv.entry.data, inv.entry.len);#if 0      MsgLog::printf("Written packet\n");#endif    inv.exit.code = RC_OK;    uint64_t ew = rdtsc();    ew -= dw;    ni->stats.txCpuCycles += ew;  }  /* Sleep if we are supposed to: */  if (!haveRoom) {#ifdef ENET_DEBUG    MsgLog::printf("net_wr: txFree: %d, pkt-len %d, sleeping\n",		   txFree, inv.entry.len);#endif    /* Wake us up when there is sufficient room in the TX FIFO for a     * complete enet packet:     */    ni->stats.wrStall++;    ni->watchDog.Disarm();    ni->watchDog.WakeupIn(500, Hydrant);    assert (ni->curInts & TxAvail);    OutCmd(ni, SetTxAvailThresh + TX_FIFO_THRESH);    Thread::Current()->SleepOn(ni->wrQ);    Thread::Current()->Yield();  }}#define INPUT_ALIGN 0x3/* ReadPacket logic: *  *   1. Skip past all bad packets in the FIFO. *   2. See if there are any remaining packets. *      if so, read them *      if not, set the RxComplete interrupt bit. *  */static voidReadPacket(NetInterface *ni, Invocation& inv){  uint64_t dw = rdtsc();    /* MsgLog::printf("Call to ReadPacket()\n"); */    if ((uint32_t)inv.exit.data & INPUT_ALIGN  ||      inv.validLen < MAX_ENET_PACKET_SZ) {    /* input buffer not aligned properly. */    inv.exit.code = RC_RequestError;    MsgLog::printf("  Bad format - inv.exit.data=0x%x inv.validLen=%d\n",		   (uint32_t)inv.exit.data, inv.validLen);    return;  }  SkipBadRxPackets(ni);  uint16_t rx_status = in16(ni->ioAddr + Wn1RxStatus);  /* We have skipped past all the bad packets.  If a good packet   * remains, yank it off the FIFO, acknowledge it, and return.   * Otherwise, enable the RxComplete interrupt and go back to sleep.   */  if ( (rx_status & RxsIncomplete) == 0) {      uint16_t len = rx_status & Rxsuint8_ts;      /* We know that the input buffer is aligned and also that it is       * of sufficient size:       */      ins32(ni->ioAddr + Wn1RxFifo, inv.exit.data, (len+3) >> 2);      ni->stats.rxPackets++;      inv.exit.len = len;      inv.exit.code = RC_OK;      OutCmd(ni, RxDiscard, true);      rx_status = in16(ni->ioAddr + Wn1RxStatus);      if ((rx_status & RxsIncomplete) == 0 && ((rx_status & RxsError) == 0))	ni->stats.rxMore++;#if 0      MsgLog::printf("  Got packet on %s, irq %d\n",		     ni->name, ni->irq);#endif      uint64_t ew = rdtsc();      ew -= dw;      ni->stats.rxCpuCycles += ew;      return;  }  ni->stats.rdStall++;  Thread::Current()->SleepOn(ni->rdQ);  /* MsgLog::printf("  Enable RxComplete interrupt\n"); */  ni->curInts |= RxComplete;  OutCmd(ni, SetIntrMask | ni->curInts);  Thread::Current()->Yield();}inline boolValidIoVec(IoVec* iov, uint32_t n, uint32_t limit){  for (uint32_t i = 0; i < n; i++, iov++) {    if (iov->len && (iov->len + iov->offset > limit)) {      MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n",		     i,		     iov->offset, iov->len,		     iov->offset + iov->len, limit);      return false;    }    /* First entry describes IOV, so don't check that! */    if (i && (iov->len < MAX_ENET_PACKET_SZ)) {      MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n",		     i,		     iov->offset, iov->len,		     iov->offset + iov->len, limit);      return false;    }    if (iov->offset & INPUT_ALIGN)	{      /* require word aligned start addr --       * buffer known to be word aligned already       */      MsgLog::printf("iov [%d] offset 0x%08x len %d sum 0x%08x limit 0x%08x\n",		     i,		     iov->offset, iov->len,		     iov->offset + iov->len, limit);      return false;    }  }  return true;}/* MultiReadPacket almost never wins on 3c509.  It's here just for * compatibility with 100Mbit cards. */static voidMultiReadPacket(NetInterface *ni, Invocation& inv){  uint64_t dw = rdtsc();  IoVec *entryVec = (IoVec *) inv.entry.data;    if (inv.entry.len < sizeof(IoVec)) {    inv.exit.code = RC_RequestError;    MsgLog::dprintf(true, "  No Send IoVec!!!\n");    return;  }    uint32_t nEntryVec = entryVec->len / sizeof(IoVec);  if ( (entryVec->len % sizeof(IoVec)) || nEntryVec > MAX_IOVEC ||       (nEntryVec == 0) ) {    inv.exit.code = RC_RequestError;    MsgLog::dprintf(true, "  Bad Send IoVec len %d\n", entryVec->len);    return;  }    if (! ValidIoVec(entryVec, nEntryVec, inv.validLen) ) {    inv.exit.code = RC_RequestError;    MsgLog::dprintf(true, "  Bad Send IoVec (ranges)\n");    return;  }    IoVec *exitVec = (IoVec *) (entryVec->offset + inv.exit.data);  uint32_t nExitVec = entryVec->len / sizeof(IoVec);  if ( (uint32_t)inv.exit.data & INPUT_ALIGN ) {    /* input buffer not aligned properly. */    inv.exit.code = RC_RequestError;    MsgLog::dprintf(true, "  misaligned rcv buffer\n");    return;  }  assert (nExitVec == nEntryVec);  IoVec tmpExitVec[MAX_IOVEC];  #define exitVec foobar  /* Careful -- must not overwrite if user entryvec == user exitvec.   * Don't dork entry 0.   */  for (uint32_t i = 1; i < nExitVec; i++) {    tmpExitVec[i].offset = entryVec[i].offset;    tmpExitVec[i].len = 0;  }  IoVec *lastEntryVec = entryVec + nEntryVec;  /* Exit block descriptor[0] entry block descriptor[0] */  tmpExitVec[0].len = entryVec->len;  tmpExitVec[0].offset = entryVec->offset;    /* Process starting with slot 1: */  IoVec *curExitVec = tmpExitVec + 1;  IoVec *curEntryVec = entryVec + 1;  bool haveData = false;    /* If we return rather than yield, it will be with ok status from   * now on.   */    inv.exit.code = RC_OK;  inv.exit.len = inv.validLen;  uint16_t rx_status;    for ( ; curEntryVec != lastEntryVec; curEntryVec++, curExitVec++) {#if 0    MsgLog::dprintf(true, "entvec=0x%08x, exvec=0x%08x\n", curEntryVec,		    curExitVec);#endif        do {      rx_status = in16(ni->ioAddr + Wn1RxStatus);      if (rx_status & RxsIncomplete) {	if (haveData) {#undef exitVec#ifdef VERBOSE	  MsgLog::dprintf(false, "Return w/ curX=0x%08x tmpX=0x%08x X=0x%08x\n",			  curExitVec, &tmpExitVec[1], &exitVec);	  int count = curExitVec - tmpExitVec;	  count--;	  MsgLog::dprintf(true, "Return w/ %d pkts\n", count);#endif	  /* Copy out to the REAL exit vec: */	  bcopy(&tmpExitVec, exitVec, tmpExitVec[0].len);#define exitVec foobar	  uint64_t ew = rdtsc();	  ew -= dw;	  ni->stats.rxCpuCycles += ew;	  return;	}	/* Else wait for at least one packet. */	ni->stats.rdStall++;	Thread::Current()->SleepOn(ni->rdQ);#ifdef VERBOSE	MsgLog::printf("Waiting for pkt on %s\n", ni->info.name);#endif	ni->curInts |= RxComplete;	OutCmd(ni, SetIntrMask | ni->curInts);	Thread::Current()->Yield();      }          if (rx_status & RxsError) {	MsgLog::printf("Skipping bad pkt\n");	SkipBadRxPackets(ni);      }    } while (rx_status & RxsError);    uint16_t len = rx_status & Rxsuint8_ts;    curExitVec->len = len;    /* We know that the input buffer is aligned and also that it is     * of sufficient size:     */    ins32(ni->ioAddr + Wn1RxFifo,	  inv.exit.data + curExitVec->offset,	  (len+3) >> 2);    ni->stats.rxPackets++;    haveData = true;    OutCmd(ni, RxDiscard, true);  }  rx_status = in16(ni->ioAddr + Wn1RxStatus);  if ((rx_status & RxsIncomplete) == 0 && ((rx_status & RxsError) == 0))    ni->stats.rxMore++;#undef exitVec#ifdef VERBOSE  MsgLog::dprintf(true, "%s (3c509): Drop out w/ %d pkts\n",		  ni->name, curExitVec - &tmpExitVec[1]);#endif  /* Copy out to the REAL exit vec: */  bcopy(&tmpExitVec, exitVec, tmpExitVec[0].len);  uint64_t ew = rdtsc();  ew -= dw;  ni->stats.rxCpuCycles += ew;}static inline voidHandleInterrupt(NetInterface * ni){  uint8_t status;			/* Status is accessable from every window */    for (;;) {    status = in16(ni->ioAddr + El3Status);    if ( (status & (IntLatch | (RxComplete&ni->curInts) | UpdateStats)) == 0)      break;    /* Only run RxPacket if we are supposed to be accepting RX interrupts: */    if (status & RxComplete & ni->curInts)      RxPacket(ni);    if (status & TxAvail) {      ni->watchDog.Disarm();      ni->wrQ.WakeAll();#ifdef ENET_DEBUG      MsgLog::printf("Got txAvail intr\n");#endif      OutCmd(ni, AckIntr | TxAvail);    }    if ( status & (AdapterFail | RxEarly | UpdateStats) ) {      if (status & UpdateStats)	UpdateStatistics(ni);      if (status & RxEarly)	MsgLog::fatal("RxEarly interrupt\n");      if (status & AdapterFail) {	/* Reset receiver and re-init the adapter: */	OutCmd(ni, RxReset);	/* Reset the RX filter to current settings: */	OutCmd(ni, SetRxFilter | ni->rxFilter);	/* Re-enable the RX FIFO: */	OutCmd(ni, RxEnable);	/* Ack this part of the interrupt: */	OutCmd(ni, AckIntr | AdapterFail);      }    }    /* Acknowledge the interrupt: */    OutCmd(ni, AckIntr | IntRequested | IntLatch);  }  /* MsgLog::dprintf(true, "3c509: Unrecognized intr, status=0x%04x\n", status); */}static voidHandleInterrupt(IntAction *ia){    /* Previous interrupt architecture line. Left in for reference.   * EL3Type        *elink = EL3Type::FindCard(interfaces[0]->irq);   */  NetInterface* ni = (NetInterface*) ia->drvr_ptr;  HandleInterrupt(ni);}static voidEnable(NetInterface * ni){  if (ni->info.niStatus & NI_ENABLED)    return;    if ( (ni->info.niStatus & NI_ATTACHED) == 0 )    return;  /* This is EXACTLY as written in the el3_open routine from linux: */  OutCmd(ni, TxReset, true);	/* long-running cmd */  OutCmd(ni, RxReset);  OutCmd(ni, SetStatusMask | 0x0); /* DISABLES INTERRUPTS */  uint32_t picen = IRQ::GetEnableMaskFromPIC();  MsgLog::printf("PICEN=0x%08x. Enable interrupt %d\n", picen, ni->irq);  IRQ::Enable(ni->irq);  picen = IRQ::GetEnableMaskFromPIC();  MsgLog::printf("PICEN=0x%08x\n", picen);#if 0  (void) /* uint32_t probeirq = */ IRQ::BeginProbe();#endif    SetWindow(ni, 0);  /* Enable the adapter: */  out16(0x1, ni->ioAddr + Wn0ConfigCtrl);  /* Set the adaptor IRQ: */  out16(ni->irq << 12 | 0x0f00, ni->ioAddr + Wn0Irq);  /* Set the station address: */  SetWindow(ni, 2);  for (int i = 0; i < 6; i++)    out8(ni->info.niAddr[i], ni->ioAddr + i);  /* Activate the transceiver: */  switch(ni->xcvr) {  case XcvrTwistedPair:    {      /* Enable link beat and jabber. */      SetWindow(ni, 4);      uint16_t curStatus = inh(ni->ioAddr + Wn4MediaType);      curStatus |= MediaStatusLK | MediaStatusJE;            out16(curStatus, ni->ioAddr + Wn4MediaType);      OutCmd(ni, StopCoax);      break;    }  case XcvrAUI:    /* AUI port enabled. Using external transceiver. */    break;  case XcvrReserved:    MsgLog::fatal("This adapter has a bad setting for the selected "		  "transceiver.\nRerun the accompanying 3Com setup "		  "program.\n");    break;  case XcvrBNC:    /* Output start coaxial transceiver command. */    OutCmd(ni, StartCoax);    /* In theory, we ought to delay here, but the lost packets are     * okay on an ethernet...     */    break;  default:    MsgLog::fatal("Bad xcvr type %d\n", ni->xcvr);    break;  }  /* Clear out the statistics buffers: */  OutCmd(ni, StatsDisable);  SetWindow(ni, 6);  for (int i = 0; i < 9; i++)    in8(ni->ioAddr + i);  in16(ni->ioAddr + 10);  in16(ni->ioAddr + 12);  SetWindow(ni, 1);  /* Set RX filter to accept individual and broadcast addresses: */  ni->rxFilter = RxIndividual | RxBroadcast;  ni->info.niStatus |= NI_BROADCAST | NI_STATION;      OutCmd(ni, SetRxFilter | ni->rxFilter);  OutCmd(ni, StatsEnable);  /* Enable TX and RX. */  OutCmd(ni, RxEnable);  OutCmd(ni, TxEnable);    OutCmd(ni, SetStatusMask | 0xff);  /* Ack all pending events, and set active interrupt mask */  OutCmd(ni, AckIntr | IntLatch | TxAvail | RxEarly | IntRequested);  /* Note: NOT RxComplete or RxEarly! */  ni->curInts = TxAvail | UpdateStats | IntLatch;  OutCmd(ni, SetIntrMask | ni->curInts);  Machine::SpinWaitMs(1);}static voidUpdateStatistics(NetInterface *ni){  IRQ::DISABLE();  OutCmd(ni, StatsDisable);  SetWindow(ni, 6);  ni->stats.txCarrierErrors            += in8(ni->ioAddr + 0);  ni->stats.txHeartbeatErrors          += in8(ni->ioAddr + 1);  /* multiple collisions */        (void) in8(ni->ioAddr + 2);  ni->stats.collisions                 += in8(ni->ioAddr + 3);  ni->stats.txWindowErrors             += in8(ni->ioAddr + 4);  ni->stats.rxFifoErrors               += in8(ni->ioAddr + 5);  ni->stats.txPackets                  += in8(ni->ioAddr + 6);  /* rxPackets */                  (void) in8(ni->ioAddr + 7);  /* txDeferrals */                (void) in8(ni->ioAddr + 8);  /* FIX: What about byt 9??? */  /* total RX octets */            (void) in16(ni->ioAddr + 10);  /* total TX octets */            (void) in16(ni->ioAddr + 12);  SetWindow(ni, 1);  OutCmd(ni, StatsEnable);  IRQ::ENABLE();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -