1 //
2 // Copyright (c) 2010-2025 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Core;
11 using Antmicro.Renode.Core.Structure;
12 using Antmicro.Renode.Core.Structure.Registers;
13 using Antmicro.Renode.Exceptions;
14 using Antmicro.Renode.Logging;
15 using Antmicro.Renode.Network;
16 using Antmicro.Renode.Peripherals.Bus;
17 using Antmicro.Renode.Peripherals.CPU;
18 using Antmicro.Renode.Peripherals.Timers;
19 using Antmicro.Renode.Time;
20 using Antmicro.Renode.Utilities;
21 using PacketDotNet;
22 
23 namespace Antmicro.Renode.Peripherals.Network
24 {
25     public partial class SynopsysDWCEthernetQualityOfService : NetworkWithPHY, IMACInterface, IKnownSize
26     {
SynopsysDWCEthernetQualityOfService(IMachine machine, long systemClockFrequency, ICPU cpuContext = null)27         public SynopsysDWCEthernetQualityOfService(IMachine machine, long systemClockFrequency, ICPU cpuContext = null) : base(machine)
28         {
29             if(DMAChannelOffsets.Length < 1 || DMAChannelOffsets.Length > MaxDMAChannels)
30             {
31                 throw new ConstructionException($"Invalid DMA channel count {DMAChannelOffsets.Length}. Expected value between 1 and {MaxDMAChannels}");
32             }
33 
34             IRQ = new GPIO();
35             MAC = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC();
36             MAC1 = EmulationManager.Instance.CurrentEmulation.MACRepository.GenerateUniqueMAC();
37             Bus = machine.GetSystemBus(this);
38             this.CpuContext = cpuContext;
39 
40             dmaChannels = new DMAChannel[DMAChannelOffsets.Length];
41             for(var i = 0; i < dmaChannels.Length; i++)
42             {
43                 dmaChannels[i] = new DMAChannel(this, i, systemClockFrequency, SeparateDMAInterrupts);
44             }
45 
46             rxIpcPacketCounterInterruptEnable = new IFlagRegisterField[NumberOfIpcCounters];
47             rxIpcByteCounterInterruptEnable = new IFlagRegisterField[NumberOfIpcCounters];
48             rxIpcPacketCounterInterrupt = new IFlagRegisterField[NumberOfIpcCounters];
49             rxIpcByteCounterInterrupt = new IFlagRegisterField[NumberOfIpcCounters];
50             rxIpcPacketCounter = new IValueRegisterField[NumberOfIpcCounters];
51             rxIpcByteCounter = new IValueRegisterField[NumberOfIpcCounters];
52             macAndMmcRegisters = new DoubleWordRegisterCollection(this, CreateRegisterMap());
53             mtlRegisters = new DoubleWordRegisterCollection(this, CreateMTLRegisterMap());
54             dmaRegisters = new DoubleWordRegisterCollection(this, CreateDMARegisterMap());
55         }
56 
ReceiveFrame(EthernetFrame frame)57         public void ReceiveFrame(EthernetFrame frame)
58         {
59             if(!rxEnable.Value)
60             {
61                 this.Log(LogLevel.Debug, "Receive: Dropping frame {0}", frame);
62                 return;
63             }
64 
65             var channelCount = dmaChannels.Length;
66 
67             // If only one channel is specified packetDuplicationControl and dmaChannelSelect fields will be null, so
68             // route the packet to the only available channel and return early
69             if(channelCount == 1)
70             {
71                 dmaChannels[0].ReceiveFrame(frame);
72                 return;
73             }
74 
75             if(packetDuplicationControl.Value)
76             {
77                 // With packet duplication enabled each set bit in the DCS field encodes a DMA channel that should receive the frame
78                 BitHelper.ForeachActiveBit(dmaChannelSelect.Value, bit => dmaChannels[bit].ReceiveFrame(frame));
79             }
80             else
81             {
82                 // DCS encodes a DMA channel number when packet duplication control is disabled
83                 var channel = (int)dmaChannelSelect.Value;
84                 if(channel >= channelCount)
85                 {
86                     this.WarningLog("DMA channel number {0} is not in range of [0, {1}). Dropping packet", channel, channelCount);
87                     return;
88                 }
89 
90                 dmaChannels[channel].ReceiveFrame(frame);
91             }
92         }
93 
Reset()94         public override void Reset()
95         {
96             ResetRegisters();
97             foreach(var channel in dmaChannels)
98             {
99                 channel.Reset();
100             }
101             UpdateInterrupts();
102         }
103 
104         public virtual long Size => 0xC00;
105         [DefaultInterrupt]
106         public GPIO IRQ { get; }
107         public MACAddress MAC { get; set; }
108         public MACAddress MAC0 => MAC;
109         public MACAddress MAC1 { get; set; }
110 
111         public event Action<EthernetFrame> FrameReady;
112 
113         // Configuration options for derived classes
114 
115         // Offset at which each channel should start. This also determinates the amount of DMA channels
116         protected virtual long[] DMAChannelOffsets => new long[]{ 0x100 };
117         protected virtual BusWidth DMABusWidth => BusWidth.Bits32;
118         protected virtual int RxQueueSize => 8192;
119         protected virtual bool SeparateDMAInterrupts => false;
120 
SendFrame(EthernetFrame frame)121         private void SendFrame(EthernetFrame frame)
122         {
123             if(loopbackEnabled.Value)
124             {
125                 ReceiveFrame(frame);
126             }
127             else
128             {
129                 FrameReady?.Invoke(frame);
130             }
131 
132             IncrementPacketCounter(txGoodPacketCounter, txGoodPacketCounterInterrupt);
133             IncrementPacketCounter(txPacketCounter, txPacketCounterInterrupt);
134             // one added to account for Start of Frame Delimiter (SFD)
135             var byteCount = 1 + (uint)frame.Bytes.Length;
136             IncrementByteCounter(txByteCounter, txByteCounterInterrupt, byteCount);
137             IncrementByteCounter(txGoodByteCounter, txGoodByteCounterInterrupt, byteCount);
138             if(frame.DestinationMAC.IsBroadcast)
139             {
140                 IncrementPacketCounter(txBroadcastPacketCounter, txBroadcastPacketCounterInterrupt);
141             }
142             else if(frame.DestinationMAC.IsMulticast)
143             {
144                 IncrementPacketCounter(txMulticastPacketCounter, txMulticastPacketCounterInterrupt);
145             }
146             else
147             {
148                 IncrementPacketCounter(txUnicastPacketCounter, txUnicastPacketCounterInterrupt);
149             }
150 #if DEBUG
151             this.Log(LogLevel.Noisy, "Transmission: frame {0}", Misc.PrettyPrintCollectionHex(frame.Bytes));
152             this.Log(LogLevel.Debug, "Transmission: frame {0}", frame);
153 #endif
154         }
155 
UpdateRxCounters(EthernetFrame frame, RxDescriptor.NormalWriteBackDescriptor writeBackStructure)156         private void UpdateRxCounters(EthernetFrame frame, RxDescriptor.NormalWriteBackDescriptor writeBackStructure)
157         {
158             if(writeBackStructure.crcError)
159             {
160                 IncrementPacketCounter(rxCrcErrorPacketCounter, rxCrcErrorPacketCounterInterrupt);
161             }
162             IncrementPacketCounter(rxPacketCounter, rxPacketCounterInterrupt);
163             // byte count excludes preamble, one added to account for Start of Frame Delimiter (SFD)
164             var byteCount = 1 + writeBackStructure.packetLength;
165             IncrementByteCounter(rxByteCounter, rxByteCounterInterrupt, byteCount);
166 
167             var isRuntPacket = writeBackStructure.packetLength <= EthernetFrame.RuntPacketMaximumSize;
168             var lengthOutOfRange = frame.Length > EthernetFrame.MaximumFrameSize;
169             var isNontypePacket = (writeBackStructure.lengthTypeField != PacketKind.TypePacket);
170             var lengthMismatch = (frame.Length != writeBackStructure.packetLength);
171 
172             var lengthError = isNontypePacket && lengthMismatch;
173             var outOfRange = isNontypePacket && lengthOutOfRange;
174             if(writeBackStructure.crcError || isRuntPacket || lengthError || outOfRange)
175             {
176                 return;
177             }
178 
179             IncrementByteCounter(rxGoodByteCounter, rxGoodByteCounterInterrupt, byteCount);
180             if(frame.DestinationMAC.IsBroadcast)
181             {
182                 IncrementPacketCounter(rxBroadcastPacketCounter, rxBroadcastPacketCounterInterrupt);
183             }
184             else if(frame.DestinationMAC.IsMulticast)
185             {
186                 IncrementPacketCounter(rxMulticastPacketCounter, rxMulticastPacketCounterInterrupt);
187             }
188             else
189             {
190                 IncrementPacketCounter(rxUnicastPacketCounter, rxUnicastPacketCounterInterrupt);
191             }
192 
193             if(writeBackStructure.ipv4HeaderPresent)
194             {
195                 IncreaseIpcCounter(IpcCounter.IpV4Good, byteCount);
196                 if(writeBackStructure.ipHeaderError)
197                 {
198                     IncreaseIpcCounter(IpcCounter.IpV4HeaderError, byteCount);
199                 }
200             }
201             if(writeBackStructure.ipv6HeaderPresent)
202             {
203                 IncreaseIpcCounter(IpcCounter.IpV6Good, byteCount);
204                 if(writeBackStructure.ipHeaderError)
205                 {
206                     IncreaseIpcCounter(IpcCounter.IpV6HeaderError, byteCount);
207                 }
208             }
209             if(writeBackStructure.payloadType ==  PayloadType.UDP)
210             {
211                 IncreaseIpcCounter(IpcCounter.UdpGood, byteCount);
212             }
213             else if(writeBackStructure.payloadType == PayloadType.TCP)
214             {
215                 IncreaseIpcCounter(IpcCounter.TcpGood, byteCount);
216             }
217             else if(writeBackStructure.payloadType == PayloadType.ICMP)
218             {
219                 IncreaseIpcCounter(IpcCounter.IcmpGood, byteCount);
220             }
221         }
222 
IncrementPacketCounter(IValueRegisterField counter, IFlagRegisterField status)223         private void IncrementPacketCounter(IValueRegisterField counter, IFlagRegisterField status)
224         {
225             counter.Value += 1;
226             status.Value |= EqualsHalfOrMaximumCounterValue(counter);
227         }
228 
IncrementByteCounter(IValueRegisterField counter, IFlagRegisterField status, uint increment)229         private void IncrementByteCounter(IValueRegisterField counter, IFlagRegisterField status, uint increment)
230         {
231             status.Value |= WouldExceedHalfOrMaximumCounterValue(counter, increment);
232             counter.Value += increment;
233         }
234 
IncreaseIpcCounter(IpcCounter type, uint byteCount)235         private void IncreaseIpcCounter(IpcCounter type, uint byteCount)
236         {
237             var index = (int)type;
238             IncrementPacketCounter(rxIpcPacketCounter[index], rxIpcPacketCounterInterrupt[index]);
239             IncrementByteCounter(rxIpcByteCounter[index], rxIpcByteCounterInterrupt[index], byteCount);
240         }
241 
CheckAnySetIpcCounterInterrupts()242         private bool CheckAnySetIpcCounterInterrupts()
243         {
244             for(var i = 0; i < NumberOfIpcCounters; i++)
245             {
246                 if((rxIpcPacketCounterInterrupt[i].Value && rxIpcPacketCounterInterruptEnable[i].Value) || (rxIpcByteCounterInterrupt[i].Value && rxIpcByteCounterInterruptEnable[i].Value))
247                 {
248                     return true;
249                 }
250             }
251             return false;
252         }
253 
EqualsHalfOrMaximumCounterValue(IValueRegisterField counter)254         private bool EqualsHalfOrMaximumCounterValue(IValueRegisterField counter)
255         {
256             return (counter.Value == CounterMaxValue) || (counter.Value == (CounterMaxValue / 2));
257         }
258 
WouldExceedHalfOrMaximumCounterValue(IValueRegisterField counter, uint increment)259         private bool WouldExceedHalfOrMaximumCounterValue(IValueRegisterField counter, uint increment)
260         {
261             return (counter.Value < CounterMaxValue && counter.Value + increment >= CounterMaxValue)
262                 || (counter.Value < CounterMaxValue / 2 && counter.Value + increment >= CounterMaxValue / 2);
263         }
264 
UpdateInterrupts()265         private void UpdateInterrupts()
266         {
267             var dmaInterrupt = false;
268             foreach(var channel in dmaChannels)
269             {
270                 dmaInterrupt |= channel.UpdateInterrupts();
271             }
272 
273             var irq = (ptpMessageTypeInterrupt.Value && ptpMessageTypeInterruptEnable.Value)   ||
274                       (lowPowerIdleInterrupt.Value && lowPowerIdleInterruptEnable.Value)       ||
275                       (timestampInterrupt.Value && timestampInterruptEnable.Value)             ||
276                       dmaInterrupt                                                             ||
277                       MMCTxInterruptStatus                                                     ||
278                       MMCRxInterruptStatus                                                     ||
279                       CheckAnySetIpcCounterInterrupts();
280 
281             this.Log(LogLevel.Noisy, "Setting IRQ: {0}", irq);
282             IRQ.Set(irq);
283         }
284 
285         private IBusController Bus { get; }
286         private ICPU CpuContext { get; }
287 
288         private bool MMCTxInterruptStatus =>
289             (txGoodPacketCounterInterrupt.Value && txGoodPacketCounterInterruptEnable.Value)           ||
290             (txGoodByteCounterInterrupt.Value && txGoodByteCounterInterruptEnable.Value)               ||
291             (txBroadcastPacketCounterInterrupt.Value && txBroadcastPacketCounterInterruptEnable.Value) ||
292             (txMulticastPacketCounterInterrupt.Value && txMulticastPacketCounterInterruptEnable.Value) ||
293             (txUnicastPacketCounterInterrupt.Value && txUnicastPacketCounterInterruptEnable.Value)     ||
294             (txPacketCounterInterrupt.Value && txPacketCounterInterruptEnable.Value)                   ||
295             (txByteCounterInterrupt.Value && txByteCounterInterruptEnable.Value);
296 
297         private bool MMCRxInterruptStatus =>
298             (rxFifoPacketCounterInterrupt.Value && rxFifoPacketCounterInterruptEnable.Value)           ||
299             (rxUnicastPacketCounterInterrupt.Value && rxUnicastPacketCounterInterruptEnable.Value)     ||
300             (rxCrcErrorPacketCounterInterrupt.Value && rxCrcErrorPacketCounterInterruptEnable.Value)   ||
301             (rxMulticastPacketCounterInterrupt.Value && rxMulticastPacketCounterInterruptEnable.Value) ||
302             (rxBroadcastPacketCounterInterrupt.Value && rxBroadcastPacketCounterInterruptEnable.Value) ||
303             (rxGoodByteCounterInterrupt.Value && rxGoodByteCounterInterruptEnable.Value)               ||
304             (rxByteCounterInterrupt.Value && rxByteCounterInterruptEnable.Value)                       ||
305             (rxPacketCounterInterrupt.Value && rxPacketCounterInterruptEnable.Value);
306 
307         private const ulong CounterMaxValue = UInt32.MaxValue;
308         private const int RxWatchdogDivider = 256;
309         private const uint EtherTypeMinimalValue = 0x600;
310 
311         // This value may be increased if required, but some changes in register creation may be required
312         private const int MaxDMAChannels = 3;
313     }
314 }
315