190 lines
6.7 KiB
Plaintext
190 lines
6.7 KiB
Plaintext
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: IntelRxRingBuffer.cs
|
|
//
|
|
// Notes:
|
|
//
|
|
// Adaptor class for the Rx ring buffer.
|
|
//
|
|
|
|
using Microsoft.Contracts;
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.Io.Net;
|
|
using Microsoft.Singularity.V1.Services;
|
|
using Microsoft.SingSharp;
|
|
|
|
using System;
|
|
|
|
namespace Microsoft.Singularity.Drivers.Network.Intel
|
|
{
|
|
internal class IntelRxRingBuffer
|
|
{
|
|
IntelRingBuffer! rxRingBuffer;
|
|
ExRef<PacketFifo>! rxPacketsInDevice;
|
|
|
|
internal IntelRxRingBuffer(uint capacity)
|
|
requires capacity > 0 && IntelRingBuffer.IsPowerOf2(capacity);
|
|
{
|
|
this.rxRingBuffer = new IntelRingBuffer(capacity);
|
|
this.rxPacketsInDevice = new ExRef<PacketFifo>(
|
|
new [ExHeap] PacketFifo((int) capacity),
|
|
false
|
|
);
|
|
}
|
|
|
|
internal void Reset()
|
|
{
|
|
rxRingBuffer.Reset();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Buffer Operations, should only be called when a lock is held
|
|
// this ring buffer.
|
|
//
|
|
private void LockedPushRecvBuffer(UIntPtr packetVirtAddr, int length)
|
|
{
|
|
PlatformService.InvalidateDCache(packetVirtAddr, (UIntPtr)length);
|
|
|
|
ulong controlBits = (ulong) ByteOrder.HostToLittleEndian(length);
|
|
|
|
rxRingBuffer.Push(packetVirtAddr, controlBits);
|
|
}
|
|
|
|
static int pass = 0;
|
|
|
|
internal void LockedPushRecvBuffer([Claims]Packet*! in ExHeap packet)
|
|
{
|
|
DebugStub.Assert(packet->FragmentCount == 1);
|
|
DebugStub.Assert(!rxRingBuffer.IsFull);
|
|
|
|
UIntPtr address;
|
|
int length;
|
|
|
|
packet->GetFragmentRange(0, out address, out length);
|
|
|
|
this.LockedPushRecvBuffer(address, length);
|
|
PacketFifo*! in ExHeap liveFifo = (!)this.rxPacketsInDevice.Acquire();
|
|
liveFifo->Push(packet);
|
|
rxPacketsInDevice.Release(liveFifo);
|
|
}
|
|
|
|
internal void Dump()
|
|
{
|
|
rxRingBuffer.Dump("rx", 8);
|
|
}
|
|
|
|
private FromDeviceFlags GetRecvPktFlags(uint stat_err_flags)
|
|
{
|
|
FromDeviceFlags fromDevFlags = 0;
|
|
|
|
if (((RxErrStatFields.CRC_ERROR | RxErrStatFields.SYMBOL_ERROR |
|
|
RxErrStatFields.SEQUENCE_ERROR | RxErrStatFields.CARRIER_EXT_ERROR |
|
|
RxErrStatFields.RX_DATA_ERROR) & stat_err_flags) != 0) {
|
|
Intel.DebugPrint("Packet Rsv Error\n");
|
|
fromDevFlags |= FromDeviceFlags.ReceiveError;
|
|
} else {
|
|
fromDevFlags |= FromDeviceFlags.ReceiveSuccess;
|
|
}
|
|
|
|
if (((stat_err_flags & RxErrStatFields.IGNORE_CHECKSUM) == 0) &&
|
|
((stat_err_flags & RxErrStatFields.IP_CHECKSUM_CALC) != 0)) {
|
|
if ((stat_err_flags & RxErrStatFields.IP_CHECKSUM_ERROR) != 0) {
|
|
Intel.DebugPrint("Bad Ip Checksum\n");
|
|
fromDevFlags |= FromDeviceFlags.BadIp4Checksum;
|
|
} else {
|
|
// Good IP checksum flag???
|
|
}
|
|
}
|
|
|
|
if (((stat_err_flags & RxErrStatFields.IGNORE_CHECKSUM) == 0) &&
|
|
((stat_err_flags & RxErrStatFields.TCP_CHECKSUM_CALC)!= 0)) {
|
|
if ((stat_err_flags & RxErrStatFields.TCP_CHECKSUM_ERROR) != 0) {
|
|
fromDevFlags |= (FromDeviceFlags.BadTcp4Checksum |
|
|
FromDeviceFlags.BadUdp4Checksum);
|
|
// don't know if UDP or TCP
|
|
Intel.DebugPrint("Bad TCP/UDP Checksum\n");
|
|
} else {
|
|
fromDevFlags |= (FromDeviceFlags.GoodTcp4Checksum |
|
|
FromDeviceFlags.GoodUdp4Checksum);
|
|
}
|
|
}
|
|
|
|
DebugStub.Assert((fromDevFlags == (FromDeviceFlags.ReceiveSuccess)) || (fromDevFlags == (FromDeviceFlags.ReceiveSuccess | FromDeviceFlags.GoodTcp4Checksum | FromDeviceFlags.GoodUdp4Checksum)));
|
|
|
|
return fromDevFlags;
|
|
}
|
|
|
|
private Packet*! in ExHeap MakePacketFromDescriptor(UIntPtr fragmentVirtAddr,
|
|
ulong controlBits)
|
|
{
|
|
PacketFifo*! in ExHeap inDevPkts = rxPacketsInDevice.Acquire();
|
|
Packet*! in ExHeap 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
|
|
DebugStub.Assert((stat_err & RxErrStatFields.END_OF_PACKET) != 0);
|
|
DebugStub.Assert(packet->GetFragmentVirtualAddress(0) == fragmentVirtAddr);
|
|
|
|
packet->FromDeviceFlags = GetRecvPktFlags(stat_err);
|
|
packet->SetFragmentLength(0, length);
|
|
|
|
rxPacketsInDevice.Release(inDevPkts);
|
|
|
|
return packet;
|
|
}
|
|
|
|
internal void LockedDrainRecvBuffer(PacketFifo*! in ExHeap toUser)
|
|
{
|
|
UIntPtr fragmentVirtAddr;
|
|
ulong controlBits;
|
|
|
|
while (rxRingBuffer.Peek(out fragmentVirtAddr, out controlBits)) {
|
|
Packet*! in ExHeap packet = MakePacketFromDescriptor(fragmentVirtAddr,
|
|
controlBits);
|
|
toUser->Push(packet);
|
|
rxRingBuffer.Pop();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Ring buffer properties
|
|
//
|
|
internal UIntPtr BaseAddress
|
|
{
|
|
get { return rxRingBuffer.BaseAddress; }
|
|
}
|
|
|
|
[Pure]
|
|
internal uint Capacity { get { return rxRingBuffer.Capacity; } }
|
|
|
|
[Pure]
|
|
internal uint Free { get { return rxRingBuffer.Free; } }
|
|
|
|
[Pure]
|
|
internal bool IsFull { get { return rxRingBuffer.IsFull; } }
|
|
|
|
[Pure]
|
|
internal uint Count { get { return rxRingBuffer.Count; } }
|
|
|
|
[Pure]
|
|
internal uint Tail { get { return rxRingBuffer.Tail; } }
|
|
|
|
[Pure]
|
|
internal uint Head { get { return rxRingBuffer.Head; } }
|
|
|
|
[Pure]
|
|
internal uint DescLength { get { return rxRingBuffer.DescLength; } }
|
|
}
|
|
}
|