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

238 lines
8.5 KiB
Plaintext
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
//////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: IntelRingBuffer.cs
//
// Notes:
//
// The underlying implementation of the ring buffer code. IntelRxRingBuffer or
// IntelTxRingBuffer should be used for actual implementation of these buffers.
using Microsoft.Contracts;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.V1.Services;
using System;
namespace Microsoft.Singularity.Drivers.Network.Intel
{
internal class IntelRingBuffer
{
/// <summary>
/// Structure used to hold Virtual-To-Physical addresses for
/// data blocks passed into an NvMacRingBuffer instance.
/// </summary>
internal struct MapEntry {
internal UIntPtr VirtualAddress;
internal UIntPtr PhysicalAddress;
internal void Initialize(UIntPtr va, UIntPtr pa)
{
this.VirtualAddress = va;
this.PhysicalAddress = pa;
}
}
private const uint DescriptorBytes = 16;
private const uint AlignmentBytes = 64; // cache line alignment
private IoMemory! region;
private MapEntry []! mapEntries;
uint capacity;
uint head;
uint tail;
uint count;
internal IntelRingBuffer(uint capacity)
requires capacity > 0 && IsPowerOf2(capacity);
{
UIntPtr length = new UIntPtr(capacity * DescriptorBytes);
IoMemory! region = (!)IoMemory.AllocatePhysical(length,
AlignmentBytes);
PlatformService.SetCacheAttributes(region.VirtualAddress,
(UIntPtr)region.Length,
false,
false);
this.region = region;
this.mapEntries = new MapEntry [capacity];
this.capacity = capacity;
this.head = 0;
this.tail = 0;
this.count = 0;
// Clear out ring buffer
for (int i = 0; i < region.Length; i += 4) {
region.Write32(i, 0);
}
}
internal void Reset()
requires this.Count == 0;
{
this.head = 0;
this.tail = 0;
for (int i = 0; i < this.region.Length; i += 4) {
this.region.Write32(i, 0);
}
}
internal void Push(UIntPtr fragmentVirtualAddress, ulong controlBits)
requires this.Count < (this.Capacity - 1); // must keep one slot empty to prevent
// head==tail which would signal an
// empty buffer.
ensures this.Count == old(this.Count) + 1;
{
UIntPtr pa = GetPhysicalAddress(fragmentVirtualAddress);
this.mapEntries[this.head].Initialize(fragmentVirtualAddress, pa);
WriteDescriptor(this.head, pa, controlBits);
this.head = (this.head + 1) & (this.Capacity - 1);
this.count++;
}
internal void Pop()
requires this.Count > 0;
ensures this.Count == old(this.count) - 1;
{
this.tail = (this.tail + 1) & (this.Capacity - 1);
this.count--;
}
// Returns true if hardware is done with this descriptor.
internal bool Peek() {
if (this.count > 0) {
uint cb = this.region.Read32((int) (this.tail * DescriptorBytes + 12));
return (cb & DescriptorStat.DESCRIPTOR_DONE) != 0;
} else {
return false;
}
}
// Returns true if hardware is done with this descriptor.
internal bool Peek(out UIntPtr fragmentVirtualAddress,
out ulong controlBits)
{
if (this.count > 0) {
UIntPtr pa;
ReadDescriptor(this.tail, out pa, out controlBits);
DebugStub.Assert(pa == this.mapEntries[tail].PhysicalAddress);
fragmentVirtualAddress = this.mapEntries[tail].VirtualAddress;
return ((controlBits & Descriptor.DESCRIPTOR_DONE) != 0);
} else {
fragmentVirtualAddress = 0;
controlBits = 0;
return false;
}
}
private void WriteDescriptor(uint index,
UIntPtr physicalAddr,
ulong controlBits)
requires (index >= 0 && index <= this.Capacity);
{
ulong addrPtr = physicalAddr.ToUInt64();
int descriptorOffset = (int)(index * DescriptorBytes);
this.region.Write64(descriptorOffset, addrPtr);
this.region.Write64(descriptorOffset + 8, controlBits);
#if false
PlatformService.CleanAndInvalidateDCache(
((UIntPtr)this.region.PhysicalAddress.Value) + descriptorOffset,
DescriptorBytes);
#endif // false
}
private void ReadDescriptor(uint index,
out UIntPtr physicalAddr,
out ulong controlBits)
{
int descriptorOffset = (int)(index * DescriptorBytes);
#if false
PlatformService.InvalidateDCache(
((UIntPtr)this.region.PhysicalAddress.Value) + descriptorOffset,
DescriptorBytes);
#endif // false
ulong addrPtr = this.region.Read64(descriptorOffset);
controlBits = this.region.Read64(descriptorOffset + 8);
physicalAddr = new UIntPtr(addrPtr);
}
internal static UIntPtr GetPhysicalAddress(UIntPtr va)
{
UIntPtr pa; // Physical address
UIntPtr paLeft; // Bytes remaining on physical page
if (!DeviceService.GetDmaPhysicalAddress(va, out pa, out paLeft) ||
pa == UIntPtr.Zero ||
paLeft < Intel.IEEE8023FrameBytes) {
throw new ApplicationException("Bad DMA pointer");
}
return pa;
}
internal void Dump(string! preamble, uint count)
{
if (count > this.capacity) {
count = this.capacity;
}
Intel.DebugWriteLine("Head {0} Tail {1}\n",
__arglist(this.Head, this.Tail));
for (uint i = 0; i < count; i++) {
ulong address = this.region.Read64((int)(i * 16));
ulong fields = this.region.Read64((int)(i * 16 + 8));
Intel.DebugWriteLine("{0}: [{1}] Address {2:x16} Sp={3:x4} Err={4:x1} Sta={5:x2} Checksum {6:x4} Length {7:x4}",
__arglist(preamble, i, address,
(fields >> 48) & 0xffff,
(fields >> 40) & 0xff,
(fields >> 32) & 0xff,
(fields >> 16) & 0xffff,
fields & 0xffff));
}
}
internal UIntPtr BaseAddress
{
get { return this.region.PhysicalAddress.Value; }
}
[Pure]
internal uint Capacity { get { return this.capacity; } }
// Note, saves one descriptor so that ring never gets completely full, which would
// lead to head == tail, which the hardware takes as meaning the ring is empty.
[Pure]
internal uint Free { get { return (this.capacity - 1) - this.count; } }
[Pure]
internal bool IsFull { get { return (this.Free == 0); } }
[Pure]
internal uint Count { get { return this.count; } }
[Pure]
internal uint Tail { get { return this.tail; } }
[Pure]
internal uint Head { get { return this.head; } }
[Pure]
internal uint DescLength { get { return (this.Capacity * DescriptorBytes); } }
[Pure]
internal static bool IsPowerOf2(uint n)
{
return (n > 0) && ((n & (n - 1)) == 0);
}
}
}