singrdk/base/Drivers/Network/Intel/IntelRxRingBuffer.sg

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; } }
}
}