private Packet MakePacketFromDescriptor(DmaMemory mem, ulong controlBits) { PacketFifo inDevPkts = rxPacketsInDevice.Acquire(); Packet packet = inDevPkts.Pop(); int length = (int)((controlBits & RxDescriptor.LENGTH_MASK) >> RxDescriptor.LENGTH_SHIFT); uint stat_err = (uint)((controlBits & RxDescriptor.ERR_STAT_MASK) >> RxDescriptor.ERR_STAT_SHIFT); // can't deal with fragments yet if ((stat_err & RxErrStatFields.END_OF_PACKET) == 0) { INucleusCalls.DebugPrintHex(40, 0xd0); DebugStub.Print("FRAGMENT\n"); throw new Exception(); } //DebugStub.Assert((stat_err & RxErrStatFields.END_OF_PACKET) != 0); //DebugStub.Assert(packet.GetFragmentVirtualAddress(0) == fragmentVirtAddr); packet.FromDeviceFlags = GetRecvPktFlags(stat_err); packet.SetFragment(0, mem.BytesRef(0, length)); rxPacketsInDevice.Release(inDevPkts); return(packet); }
/////////////////////////////////////////////////////////////////////// // // Tx buffer operations // internal void PopulateTsmtBuffer(PacketFifo fromUser) { DebugStub.Assert(this.ioRunning); // since no transmit interrupts are sent, we must check for // transmission events here if (txRingBuffer.NewTransmitEvent()) { NicEventType ev = NicEventType.TransmitEvent; if (eventRelay != null) { eventRelay.ForwardEvent(ev); } } using (txRingBuffer.thisLock.Lock()) { while (fromUser.Count > 0) { Packet packet = fromUser.Pop(); txRingBuffer.LockedPushTsmtBuffer(packet); } // update hardware tail pointer // so that hardware knows it has new packets to transmit Write32(Register.TSMT_DESC_TAIL, txRingBuffer.Head); // sw head is hw tail } }
//push a single packet onto the ring void IAdapter.PopulateTxRing(Bytes header, Bytes data) { try { PacketFifo txFree = this.txFreeFifo.Acquire(); PacketFifo txToDevice = this.txFifo.Acquire(); DebugPrint("populate tx ring\n"); try { Packet packet = txFree.Pop(); packet.SetFragment(0, header); packet.SetFragment(1, data); txToDevice.Push(packet); } finally { this.txFreeFifo.Release(txFree); this.txFifo.Release(txToDevice); } } catch (Exception e) { DebugStub.Print("Populate tx ring failed?? {0}\n", DebugStub.ArgList(e)); DebugStub.Break(); } //When to exchange? //how do we best manage the tradeoff of throughput and latency? //to begin let's just send one at a time. //I think i'd rather have another thread.... using (thisLock.Lock()) { TxExchange(); } }
private Packet MakePacketFromDescriptor(ulong controlBits) { PacketFifo inDevPkts = txPacketsInDevice.Acquire(); Packet packet = inDevPkts.Pop(); // int length = (int) ((controlBits & TxDescriptor.LENGTH_MASK) // >> TxDescriptor.LENGTH_SHIFT); int stat_err = (int)((controlBits & TxDescriptor.ERR_STAT_MASK) >> TxDescriptor.ERR_STAT_SHIFT); //DebugStub.Assert(packet.GetFragmentVirtualAddress(0) == fragmentVirtAddr); if (((TxStatErrFields.LATE_COLLISION | TxStatErrFields.EXCESS_COLLISIONS | TxStatErrFields.TRANSMIT_UNDERRUN) & stat_err) == 0) { packet.FromDeviceFlags = FromDeviceFlags.TransmitSuccess; } else { packet.FromDeviceFlags = FromDeviceFlags.TransmitError; } txPacketsInDevice.Release(inDevPkts); return(packet); }
//push a single packet onto the ring void IAdapter.PopulateTxRing(Bytes header, Bytes data) { try { PacketFifo txFree = this.txFreeFifo.Acquire(); PacketFifo txCoalesce = this.txCoalesceFifo.Acquire(); try { DebugStub.Assert(txFree.Count > 0); int cnt = 0; while (txFree.Count <= 0) { //try again... //this happens when we're hammering the outgoing connection this.txCoalesceFifo.Release(txCoalesce); this.txFreeFifo.Release(txFree); this.muxEvent.Set(); Thread.Yield(); txFree = this.txFreeFifo.Acquire(); txCoalesce = this.txCoalesceFifo.Acquire(); if (cnt > 100) { DebugStub.Print("txFree empty???\n"); //DebugStub.Break(); } cnt++; } Packet packet = txFree.Pop(); packet.SetFragment(0, header); packet.SetFragment(1, data); if ((txCoalesce.Count + 1) > txCoalesce.Capacity) { DebugStub.Break(); } DebugStub.Assert((txCoalesce.Count + 1) <= txCoalesce.Capacity); txCoalesce.Push(packet); } catch { DebugStub.Print("failure in populate tx ring\n"); DebugStub.Break(); DebugStub.Assert(false); } finally { this.txCoalesceFifo.Release(txCoalesce); this.txFreeFifo.Release(txFree); //notify the mux that there are waiting packets this.muxEvent.Set(); } } catch (Exception e) { DebugStub.Print("Populate tx ring failed?? {0}\n", DebugStub.ArgList(e)); DebugStub.Break(); } }
/////////////////////////////////////////////////////////////////////// // // Rx buffer operations // internal void PopulateRecvBuffer(PacketFifo fromUser) { if (fromUser.Count < 1) { return; } using (rxRingBuffer.thisLock.Lock()) { while (fromUser.Count > 0) { rxRingBuffer.LockedPushRecvBuffer(fromUser.Pop()); } Write32(Register.RECV_DESC_TAIL, rxRingBuffer.Head); } }
// Get the received packets from the adapter void DeMuxReceivedPackets() { //Grab the latest set of packets RxExchange(); PacketFifo newPackets = this.rxFifo.Acquire(); try { int count = newPackets.Count; for (int i = 0; i < count; i++) { Packet packet = newPackets.Pop(); // If packet from device has an error // recycle it right away. FromDeviceFlags fromFlags = packet.FromDeviceFlags; if ((fromFlags & FromDeviceFlags.ReceiveError) != 0) { DebugStub.Print("Packet had error???\n"); newPackets.Push(packet); continue; } Bytes data = packet.ReleaseFragment(0); Ethernet.ProcessIncomingPacket(data, this); #if false if (filterAdapter == null || filterAdapter.ProcessIncomingPacket(data)) { Ethernet.ProcessIncomingPacket(data, this); } else { //delete data; } #endif //XXX Totally inefficient first try immediately replaces //the lost data. Bytes nxtPacket = new Bytes(new byte[this.mtu]); packet.SetFragment(0, nxtPacket); newPackets.Push(packet); } } finally { this.rxFifo.Release(newPackets); } }