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 using IPProtocolType = PacketDotNet.IPProtocolType; 24 25 namespace Antmicro.Renode.Peripherals.Network 26 { 27 public partial class SynopsysDWCEthernetQualityOfService 28 { 29 protected readonly DMAChannel[] dmaChannels; 30 31 protected enum BusWidth 32 { 33 Bits32 = 4, 34 Bits64 = 8, 35 Bits128 = 16, 36 } 37 38 protected enum DMAChannelInterruptMode 39 { 40 Pulse = 0b00, 41 Level = 0b01, 42 LevelAndReassert = 0b10, 43 Reserved = 0b11, 44 } 45 46 private enum DMAState 47 { 48 Stopped = 0, 49 Running = 1, 50 ProcessingIntermediate = 2, 51 ProcessingSecond = 4, 52 Suspended = 8, 53 } 54 55 protected class DMAChannel 56 { DMAChannel(SynopsysDWCEthernetQualityOfService parent, int channelNumber, long systemClockFrequency, bool hasInterrupts)57 public DMAChannel(SynopsysDWCEthernetQualityOfService parent, int channelNumber, long systemClockFrequency, bool hasInterrupts) 58 { 59 this.parent = parent; 60 this.channelNumber = channelNumber; 61 this.hasInterrupts = hasInterrupts; 62 63 if(hasInterrupts) 64 { 65 TxIRQ = new GPIO(); 66 RxIRQ = new GPIO(); 67 } 68 69 incomingFrames = new Queue<EthernetFrame>(); 70 rxWatchdog = new LimitTimer(parent.machine.ClockSource, systemClockFrequency, parent, $"DMA Channel {channelNumber}: rx-watchdog", enabled: false, workMode: WorkMode.OneShot, eventEnabled: true, autoUpdate: true, divider: RxWatchdogDivider); 71 rxWatchdog.LimitReached += delegate 72 { 73 this.Log(LogLevel.Noisy, "Receive: Watchdog reached limit."); 74 rxInterrupt.Value = true; 75 parent.UpdateInterrupts(); 76 }; 77 } 78 Reset()79 public void Reset() 80 { 81 rxFinishedRing = true; 82 txFinishedRing = true; 83 txState = DMAState.Stopped; 84 rxState = DMAState.Stopped; 85 rxOffset = 0; 86 latestTxContext = null; 87 rxWatchdog.Reset(); 88 incomingFrames.Clear(); 89 rxQueueLength = 0; 90 frameAssembler = null; 91 } 92 DefineChannelRegisters(ref Dictionary<long, DoubleWordRegister> map)93 public void DefineChannelRegisters(ref Dictionary<long, DoubleWordRegister> map) 94 { 95 var offset = parent.DMAChannelOffsets[channelNumber]; 96 map = map.Concat(new Dictionary<long, DoubleWordRegister>() 97 { 98 {(long)RegistersDMAChannel.Control + offset, new DoubleWordRegister(parent) 99 .WithValueField(0, 14, out maximumSegmentSize, name: "DMACCR.MSS (Maximum Segment Size)") 100 .WithReservedBits(14, 2) 101 .WithFlag(16, out programmableBurstLengthTimes8, name: "DMACCR.PBLX8 (8xPBL mode)") 102 .WithReservedBits(17, 1) 103 .WithValueField(18, 3, out descriptorSkipLength, name: "DMACCR.DSL (Descriptor Skip Length)") 104 .WithReservedBits(21, 11) 105 }, 106 {(long)RegistersDMAChannel.TransmitControl + offset, new DoubleWordRegister(parent) 107 .WithFlag(0, out startTx, changeCallback: (_, __) => 108 { 109 if(startTx.Value) 110 { 111 txFinishedRing = txDescriptorRingCurrent.Value == txDescriptorRingTail.Value; 112 StartTx(); 113 } 114 }, 115 name: "DMACTxCR.ST (Start or Stop Transmission Command)") 116 .WithReservedBits(1, 3) 117 .WithFlag(4, out operateOnSecondPacket, name: "DMACTxCR.OSF (Operate on Second Packet)") 118 .WithReservedBits(5, 7) 119 .WithFlag(12, out tcpSegmentationEnable, name: "DMACTxCR.TSE (TCP Segmentation Enabled)") 120 .WithReservedBits(13, 3) 121 .WithValueField(16, 6, out txProgrammableBurstLength, name: "DMACTxCR.TXPBL (Transmit Programmable Burst Length)") 122 .WithReservedBits(22, 10) 123 }, 124 {(long)RegistersDMAChannel.ReceiveControl + offset, new DoubleWordRegister(parent) 125 .WithFlag(0, out startRx, changeCallback: (_, __) => 126 { 127 if(startRx.Value) 128 { 129 rxFinishedRing = rxDescriptorRingCurrent.Value == rxDescriptorRingTail.Value; 130 StartRx(); 131 } 132 }, 133 name: "DMACRxCR.SR (Start or Stop Receive Command)") 134 .WithValueField(1, 14, out rxBufferSize, writeCallback: (_, __) => 135 { 136 if(rxBufferSize.Value % 4 != 0) 137 { 138 this.Log(LogLevel.Warning, "Receive buffer size must be a multiple of 4. Ignoring LSBs, but this behavior is undefined."); 139 rxBufferSize.Value &= ~0x3UL; 140 } 141 }, 142 name: "DMACRxCR.RBSZ (Receive Buffer size)") 143 .WithReservedBits(15, 1) 144 .WithValueField(16, 6, out rxProgrammableBurstLength, name: "DMACRxCR.RXPBL (RXPBL)") 145 .WithReservedBits(22, 9) 146 .WithTaggedFlag("DMACRxCR.RPF (DMA Rx Channel Packet Flush)", 31) 147 }, 148 {(long)RegistersDMAChannel.TxDescriptorListAddress + offset, new DoubleWordRegister(parent) 149 .WithValueField(0, 32, out txDescriptorRingStart, writeCallback: (_, __) => 150 { 151 txDescriptorRingCurrent.Value = txDescriptorRingStart.Value; 152 }, 153 name: "DMACTxDLAR.TDESLA (Start of Transmit List)") 154 }, 155 {(long)RegistersDMAChannel.RxDescriptorListAddress + offset, new DoubleWordRegister(parent) 156 .WithValueField(0, 32, out rxDescriptorRingStart, writeCallback: (_, __) => 157 { 158 rxDescriptorRingCurrent.Value = rxDescriptorRingStart.Value; 159 }, 160 name: "DMACRxDLAR.RDESLA (Start of Receive List)") 161 }, 162 {(long)RegistersDMAChannel.TxDescriptorTailPointer + offset, new DoubleWordRegister(parent) 163 .WithValueField(0, 32, out txDescriptorRingTail, changeCallback: (previousValue, _) => 164 { 165 var clearTxFinishedRing = txDescriptorRingTail.Value != txDescriptorRingCurrent.Value; 166 if((txState & DMAState.Suspended) != 0 || clearTxFinishedRing) 167 { 168 txFinishedRing &= !clearTxFinishedRing; 169 StartTx(); 170 } 171 this.Log(LogLevel.Debug, "Transmit Tail register (DMACTxDTPR.TDT) set to: 0x{0:X}", txDescriptorRingTail.Value); 172 }, name: "DMACTxDTPR.TDT (Transmit Descriptor Tail Pointer)") 173 }, 174 {(long)RegistersDMAChannel.RxDescriptorTailPointer + offset, new DoubleWordRegister(parent) 175 .WithValueField(0, 32, out rxDescriptorRingTail, changeCallback: (previousValue, _) => 176 { 177 var clearRxFinishedRing = rxDescriptorRingTail.Value != rxDescriptorRingCurrent.Value; 178 if((rxState & DMAState.Suspended) != 0 || clearRxFinishedRing) 179 { 180 rxFinishedRing &= !clearRxFinishedRing; 181 StartRx(); 182 } 183 this.Log(LogLevel.Debug, "Receive Tail register (DMACRxDTPR.RDT) set to: 0x{0:X}", rxDescriptorRingTail.Value); 184 }, name: "DMACRxDTPR.RDT (Receive Descriptor Tail Pointer)") 185 }, 186 {(long)RegistersDMAChannel.TxDescriptorRingLength + offset, new DoubleWordRegister(parent) 187 .WithValueField(0, 10, out txDescriptorRingLength, name: "DMACTxRLR.TDRL (Transmit Descriptor Ring Length)") 188 .WithReservedBits(10, 22) 189 }, 190 {(long)RegistersDMAChannel.RxDescriptorRingLength + offset, new DoubleWordRegister(parent) 191 .WithValueField(0, 10, out rxDescriptorRingLength, name: "DMACRxRLR.RDRL (Receive Descriptor Ring Length)") 192 .WithReservedBits(10, 6) 193 .WithValueField(16, 8, out alternateRxBufferSize, name: "DMACRxRLR.ARBS (Alternate Receive Buffer Size)") 194 .WithReservedBits(24, 8) 195 }, 196 {(long)RegistersDMAChannel.InterruptEnable + offset, new DoubleWordRegister(parent) 197 .WithFlag(0, out txInterruptEnable, name: "DMACIER.TIE (Transmit Interrupt Enable)") 198 .WithFlag(1, out txProcessStoppedEnable, name: "DMACIER.TXSE (Transmit Stopped Enable)") 199 .WithFlag(2, out txBufferUnavailableEnable, name: "DMACIER.TBUE (Transmit Buffer Unavailable Enable)") 200 .WithReservedBits(3, 3) 201 .WithFlag(6, out rxInterruptEnable, name: "DMACIER.RIE (Receive Interrupt Enable)") 202 .WithFlag(7, out rxBufferUnavailableEnable, name: "DMACIER.RBUE (Receive Buffer Unavailable Enable)") 203 .WithFlag(8, out rxProcessStoppedEnable, name: "DMACIER.RSE (Receive Stopped Enable)") 204 .WithFlag(9, out rxWatchdogTimeoutEnable, name: "DMACIER.RWTE (Receive Watchdog Timeout Enable)") 205 .WithFlag(10, out earlyTxInterruptEnable, name: "DMACIER.ETIE (Early Transmit Interrupt Enable)") 206 .WithFlag(11, out earlyRxInterruptEnable, name: "DMACIER.ERIE (Early Receive Interrupt Enable)") 207 .WithFlag(12, out fatalBusErrorEnable, name: "DMACIER.FBEE (Fatal Bus Error Enable)") 208 .WithFlag(13, out contextDescriptorErrorEnable, name: "DMACIER.CDEE (Context Descriptor Error Enable)") 209 .WithFlag(14, out abnormalInterruptSummaryEnable, name: "DMACIER.AIE (Abnormal Interrupt Summary Enable)") 210 .WithFlag(15, out normalInterruptSummaryEnable, name: "DMACIER.NIE (Normal Interrupt Summary Enable)") 211 .WithReservedBits(16, 16) 212 .WithChangeCallback((_, __) => parent.UpdateInterrupts()) 213 }, 214 {(long)RegistersDMAChannel.RxInterruptWatchdogTimer + offset, new DoubleWordRegister(parent) 215 .WithValueField(0, 8, out rxWatchdogCounter, changeCallback: (_, __) => 216 { 217 rxWatchdog.Limit = rxWatchdogCounter.Value; 218 }, 219 name: "DMACRxIWTR.RWT (Receive Interrupt Watchdog Timer Count)") 220 .WithReservedBits(8, 8) 221 .WithValueField(16, 2, out rxWatchdogCounterUnit, changeCallback: (_, __) => 222 { 223 rxWatchdog.Divider = RxWatchdogDivider << (byte)rxWatchdogCounterUnit.Value; 224 }, 225 name: "DMACRxIWTR.RWTU (Receive Interrupt Watchdog Timer Count Units)") 226 .WithReservedBits(18, 14) 227 }, 228 {(long)RegistersDMAChannel.CurrentApplicationTransmitDescriptor + offset, new DoubleWordRegister(parent) 229 .WithValueField(0, 32, out txDescriptorRingCurrent, FieldMode.Read, name: "DMACCATxDR.CURTDESAPTR (Application Transmit Descriptor Address Pointer)") 230 }, 231 {(long)RegistersDMAChannel.CurrentApplicationReceiveDescriptor + offset, new DoubleWordRegister(parent) 232 .WithValueField(0, 32, out rxDescriptorRingCurrent, FieldMode.Read, name: "DMACCARxDR.CURRDESAPTR (Application Receive Descriptor Address Pointer)") 233 }, 234 {(long)RegistersDMAChannel.CurrentApplicationTransmitBuffer + offset, new DoubleWordRegister(parent) 235 .WithValueField(0, 32, out txCurrentBuffer, FieldMode.Read, name: "DMACCATxBR.CURTBUFAPTR (Application Transmit Buffer Address Pointer)") 236 }, 237 {(long)RegistersDMAChannel.CurrentApplicationReceiveBuffer + offset, new DoubleWordRegister(parent) 238 .WithValueField(0, 32, out rxCurrentBuffer, FieldMode.Read, name: "DMACCARxBR.CURRBUFAPTR (Application Receive Buffer Address Pointer)") 239 }, 240 {(long)RegistersDMAChannel.Status + offset, new DoubleWordRegister(parent) 241 .WithFlag(0, out txInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.TI (Transmit Interrupt)") 242 .WithFlag(1, out txProcessStopped, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.TPS (Transmit Process Stopped)") 243 .WithFlag(2, out txBufferUnavailable, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.TBU (Transmit Buffer Unavailable)") 244 .WithReservedBits(3, 3) 245 .WithFlag(6, out rxInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.RI (Receive Interrupt)") 246 .WithFlag(7, out rxBufferUnavailable, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.RBU (Receive Buffer Unavailable)") 247 .WithFlag(8, out rxProcessStopped, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.RPS (Receive Process Stopped)") 248 .WithFlag(9, out rxWatchdogTimeout, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.RWT (Receive Watchdog Timeout)") 249 .WithFlag(10, out earlyTxInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.ET (Early Transmit Interrupt)") 250 .WithFlag(11, out earlyRxInterrupt, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.ER (Early Receive Interrupt)") 251 .WithFlag(12, out fatalBusError, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.FBE (Fatal Bus Error)") 252 .WithFlag(13, out contextDescriptorError, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.CDE (Context Descriptor Error)") 253 .WithFlag(14, out abnormalInterruptSummary, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.AIS (Abnormal Interrupt Summary)") 254 .WithFlag(15, out normalInterruptSummary, FieldMode.Read | FieldMode.WriteOneToClear, name: "DMACSR.NIS (Normal Interrupt Summary)") 255 .WithTag("DMACSR.TEB (Tx DMA Error Bits)", 16, 3) 256 .WithTag("DMACSR.REB (Rx DMA Error Bits)", 19, 3) 257 .WithReservedBits(22, 10) 258 .WithChangeCallback((_, __) => parent.UpdateInterrupts()) 259 }, 260 {(long)RegistersDMAChannel.MissedFrameCount + offset, new DoubleWordRegister(parent) 261 .WithTag("DMACMFCR.MFC (Dropped Packet Counters)", 0, 11) 262 .WithReservedBits(11, 4) 263 .WithTaggedFlag("DMACMFCR.MFCO (Overflow status of the MFC Counter)", 15) 264 .WithReservedBits(16, 16) 265 } 266 }).ToDictionary(x => x.Key, x => x.Value); 267 } 268 ReceiveFrame(EthernetFrame frame)269 public void ReceiveFrame(EthernetFrame frame) 270 { 271 if(rxQueueLength + frame.Length > parent.RxQueueSize) 272 { 273 parent.IncrementPacketCounter(parent.rxFifoPacketCounter, parent.rxFifoPacketCounterInterrupt); 274 this.Log(LogLevel.Debug, "Receive: Dropping overflow frame {0}", frame); 275 parent.UpdateInterrupts(); 276 return; 277 } 278 279 this.Log(LogLevel.Debug, "Receive: Incoming frame {0}", frame); 280 incomingFrames.Enqueue(frame); 281 rxQueueLength += frame.Bytes.Length; 282 StartRx(); 283 } 284 UpdateInterrupts()285 public bool UpdateInterrupts() 286 { 287 // Depending on the DMA interrupt mode transmit/receive completed condition may not 288 // contribute to the common interrupt. Those masks are used to block those conditions from 289 // influencing the common interrupt state. 290 var txMask = true; 291 var rxMask = true; 292 293 if(hasInterrupts) 294 { 295 switch(parent.dmaInterruptMode.Value) 296 { 297 case DMAChannelInterruptMode.Pulse: 298 if(txInterrupt.Value) 299 { 300 TxIRQ.Blink(); 301 this.Log(LogLevel.Debug, "Blinking TxIRQ"); 302 } 303 if(rxInterrupt.Value) 304 { 305 RxIRQ.Blink(); 306 this.Log(LogLevel.Debug, "Blinking RxIRQ"); 307 } 308 break; 309 case DMAChannelInterruptMode.Level: 310 case DMAChannelInterruptMode.LevelAndReassert: 311 { 312 var txState = txInterrupt.Value && txInterruptEnable.Value && normalInterruptSummaryEnable.Value; 313 var rxState = rxInterrupt.Value && rxInterruptEnable.Value && normalInterruptSummaryEnable.Value; 314 TxIRQ.Set(txState); 315 RxIRQ.Set(rxState); 316 this.Log(LogLevel.Debug, "TxIRQ: {0}, RxIRQ: {1}", txState ? "setting" : "unsetting", rxState ? "setting" : "unsetting"); 317 // In both Level and LevelAndReassert transmit/receive completed conditions are only used for channel specific interrupts 318 // and don't contribute to the common interrupt. Mask their influence 319 txMask = false; 320 rxMask = false; 321 break; 322 } 323 default: 324 this.Log(LogLevel.Warning, "Invalid interrupt mode value {0}", parent.dmaInterruptMode.Value); 325 break; 326 } 327 } 328 329 normalInterruptSummary.Value |= GetNormalInterruptSummary(); 330 abnormalInterruptSummary.Value |= (txProcessStopped.Value && txProcessStoppedEnable.Value) || 331 (rxBufferUnavailable.Value && rxBufferUnavailableEnable.Value) || 332 (rxProcessStopped.Value && rxProcessStoppedEnable.Value) || 333 (earlyTxInterrupt.Value && earlyTxInterruptEnable.Value) || 334 (fatalBusError.Value && fatalBusErrorEnable.Value) || 335 (contextDescriptorError.Value && contextDescriptorErrorEnable.Value); 336 337 return (rxWatchdogTimeout.Value && rxWatchdogTimeoutEnable.Value) || 338 (abnormalInterruptSummary.Value && abnormalInterruptSummaryEnable.Value) || 339 (GetNormalInterruptSummary(txMask, rxMask) && normalInterruptSummaryEnable.Value); 340 } 341 342 public DMATxProcessState DmaTxState => (txState == DMAState.Stopped) ? DMATxProcessState.Stopped : DMATxProcessState.Suspended; 343 public DMARxProcessState DmaRxState => (rxState == DMAState.Stopped) ? DMARxProcessState.Stopped : 344 ((incomingFrames.Count == 0) ? DMARxProcessState.WaitingForPacket : DMARxProcessState.Suspended); 345 346 public bool Interrupts => 347 txInterrupt.Value || 348 txProcessStopped.Value || 349 txBufferUnavailable.Value || 350 rxInterrupt.Value || 351 rxBufferUnavailable.Value || 352 rxProcessStopped.Value || 353 rxWatchdogTimeout.Value || 354 earlyTxInterrupt.Value || 355 earlyRxInterrupt.Value || 356 fatalBusError.Value || 357 abnormalInterruptSummary.Value || 358 normalInterruptSummary.Value; 359 360 public GPIO TxIRQ { get; } 361 public GPIO RxIRQ { get; } 362 GetTxDescriptor(ulong index = 0)363 private TxDescriptor GetTxDescriptor(ulong index = 0) 364 { 365 var descriptor = new TxDescriptor(parent.Bus, txDescriptorRingCurrent.Value, parent.CpuContext); 366 descriptor.Fetch(); 367 return descriptor; 368 } 369 GetRxDescriptor()370 private RxDescriptor GetRxDescriptor() 371 { 372 var descriptor = new RxDescriptor(parent.Bus, rxDescriptorRingCurrent.Value, parent.CpuContext); 373 descriptor.Fetch(); 374 return descriptor; 375 } 376 IncreaseTxDescriptorPointer()377 private void IncreaseTxDescriptorPointer() 378 { 379 IncreaseDescriptorPointer(txDescriptorRingCurrent, txDescriptorRingStart, txDescriptorRingLength, "TX"); 380 txFinishedRing = txDescriptorRingCurrent.Value == txDescriptorRingTail.Value; 381 } 382 IncreaseRxDescriptorPointer()383 private void IncreaseRxDescriptorPointer() 384 { 385 IncreaseDescriptorPointer(rxDescriptorRingCurrent, rxDescriptorRingStart, rxDescriptorRingLength, "RX"); 386 rxFinishedRing = rxDescriptorRingCurrent.Value == rxDescriptorRingTail.Value; 387 } 388 IncreaseDescriptorPointer(IValueRegisterField current, IValueRegisterField start, IValueRegisterField length, string name)389 private void IncreaseDescriptorPointer(IValueRegisterField current, IValueRegisterField start, IValueRegisterField length, string name) 390 { 391 var size = descriptorSkipLength.Value * (ulong)parent.DMABusWidth + Descriptor.Size; 392 var offset = current.Value - start.Value; 393 offset += size; 394 // The docs state that: "If you want to have 10 descriptors, program it to a value of 0x9" - so it always should be +1 descriptor than obtained from the register 395 offset %= (length.Value + 1) * size; 396 this.Log(LogLevel.Noisy, "{0} Descriptor pointer was 0x{1:X}, now is 0x{2:X}, size 0x{3:X}, ring length 0x{4:x}", name, current.Value, start.Value + offset, size, length.Value); 397 current.Value = start.Value + offset; 398 } 399 TriggerRxWatchdog()400 private void TriggerRxWatchdog() 401 { 402 rxWatchdog.Value = rxWatchdogCounter.Value; 403 rxWatchdog.Enabled = rxWatchdogCounter.Value != 0 || rxWatchdogCounterUnit.Value != 0; 404 } 405 StartRx()406 private void StartRx() 407 { 408 if(!parent.rxEnable.Value) 409 { 410 rxState = DMAState.Stopped; 411 this.Log(LogLevel.Noisy, "Receive: Rx DMA is not enabled."); 412 return; 413 } 414 if(!startRx.Value) 415 { 416 rxState = DMAState.Stopped; 417 this.Log(LogLevel.Noisy, "Receive: Rx DMA is not started."); 418 return; 419 } 420 if(rxState == DMAState.Stopped) 421 { 422 rxState = DMAState.Running; 423 rxDescriptorRingCurrent.Value = rxDescriptorRingStart.Value; 424 this.Log(LogLevel.Debug, "Receive: Starting DMA at 0x{0:X}.", rxDescriptorRingCurrent.Value); 425 } 426 else 427 { 428 this.Log(LogLevel.Debug, "Receive: Resuming DMA at 0x{0:X}.", rxDescriptorRingCurrent.Value); 429 } 430 431 if(incomingFrames.Count == 0) 432 { 433 this.Log(LogLevel.Noisy, "Receive: No frames to process."); 434 rxState |= DMAState.Suspended; 435 return; 436 } 437 var frame = incomingFrames.Peek(); 438 var bytes = frame.Bytes; 439 var isFirst = true; 440 while(!rxFinishedRing && parent.rxEnable.Value && startRx.Value) 441 { 442 var descriptor = GetRxDescriptor(); 443 444 if(!descriptor.IsOwnedByDMA.Value) 445 { 446 this.Log(LogLevel.Debug, "Receive: Loaded descriptor is not owned by DMA."); 447 rxBufferUnavailable.Value = true; 448 rxState |= DMAState.Suspended; 449 break; 450 } 451 rxState &= ~DMAState.Suspended; 452 var structure = descriptor.GetNormalReadDescriptor(); 453 #if DEBUG 454 this.Log(LogLevel.Noisy, "Receive: Loaded {0} from 0x{1:X}.", structure, descriptor.Address); 455 #endif 456 457 var bufferAddress = 0UL; 458 var bufferSize = 0UL; 459 var invalidDescriptor = structure.buffer1Address == UInt32.MaxValue || structure.buffer2Address == UInt32.MaxValue; 460 if(!invalidDescriptor && structure.buffer1Address != 0 && structure.buffer1AddressValid) 461 { 462 bufferAddress = structure.buffer1Address; 463 bufferSize = RxBuffer1Size; 464 } 465 else if(!invalidDescriptor && structure.buffer2Address != 0 && structure.buffer2AddressValid) 466 { 467 bufferAddress = structure.buffer2Address; 468 bufferSize = RxBuffer2Size; 469 } 470 else 471 { 472 contextDescriptorError.Value |= invalidDescriptor; 473 this.Log(LogLevel.Debug, "Receive: Loaded descriptor doesn't provide a valid buffer."); 474 structure.owner = DescriptorOwner.Application; 475 #if DEBUG 476 this.Log(LogLevel.Noisy, "Receive: Writing {0} to 0x{1:X}.", structure, descriptor.Address); 477 #endif 478 descriptor.SetDescriptor(structure); 479 descriptor.Write(); 480 IncreaseRxDescriptorPointer(); 481 continue; 482 } 483 rxCurrentBuffer.Value = bufferAddress; 484 485 if(isFirst) 486 { 487 earlyRxInterrupt.Value = true; 488 parent.UpdateInterrupts(); 489 } 490 491 if(rxOffset >= (ulong)bytes.Length) 492 { 493 if(parent.enableTimestamp.Value && (parent.enableTimestampForAll.Value /* || is PTP */)) 494 { 495 this.Log(LogLevel.Error, "Receive: Timestamping is not supported."); 496 var contextStructure = descriptor.GetAsContextDescriptor(); 497 contextStructure.contextType = true; 498 contextStructure.owner = DescriptorOwner.Application; 499 #if DEBUG 500 this.Log(LogLevel.Noisy, "Receive: Writing {0} to 0x{1:X}.", contextStructure, descriptor.Address); 501 #endif 502 descriptor.SetDescriptor(contextStructure); 503 descriptor.Write(); 504 IncreaseRxDescriptorPointer(); 505 } 506 rxOffset = 0; 507 incomingFrames.Dequeue(); 508 rxQueueLength -= bytes.Length; 509 510 if(incomingFrames.Count == 0) 511 { 512 this.Log(LogLevel.Noisy, "Receive: Finished handling frame, no more frames to process."); 513 break; 514 } 515 this.Log(LogLevel.Noisy, "Receive: Finished handling frame, processing next frame."); 516 frame = incomingFrames.Peek(); 517 isFirst = true; 518 bytes = frame.Bytes; 519 continue; 520 } 521 522 var bytesWritten = Math.Min((ulong)bytes.Length - rxOffset, bufferSize); 523 parent.Bus.WriteBytes(bytes, bufferAddress, (int)rxOffset, (long)bytesWritten, true, parent.CpuContext); 524 this.Log(LogLevel.Noisy, "Receive: Writing frame[0x{0:X}, 0x{1:X}) at 0x{2:X}.", rxOffset, rxOffset + bytesWritten, bufferAddress); 525 rxOffset += bytesWritten; 526 527 var writeBackStructure = descriptor.GetAsNormalWriteBackDescriptor(); 528 writeBackStructure.owner = DescriptorOwner.Application; 529 writeBackStructure.firstDescriptor = isFirst; 530 writeBackStructure.lastDescriptor = rxOffset == (ulong)bytes.Length; 531 writeBackStructure.contextType = false;; 532 writeBackStructure.receiveStatusSegment0Valid = true; 533 writeBackStructure.receiveStatusSegment1Valid = true; 534 writeBackStructure.receiveStatusSegment2Valid = true; 535 isFirst = false; 536 537 writeBackStructure.packetLength = (uint)bytes.Length; 538 writeBackStructure.outerVlanTag = 0x0; 539 writeBackStructure.innerVlanTag = 0x0; 540 writeBackStructure.oamSubtypeCodeOrMACControlPacketOpcode = (uint)frame.UnderlyingPacket.Type; 541 writeBackStructure.ipHeaderError = false; 542 writeBackStructure.ipv4HeaderPresent = frame.UnderlyingPacket.Type == EthernetPacketType.IpV4; 543 writeBackStructure.ipv6HeaderPresent = frame.UnderlyingPacket.Type == EthernetPacketType.IpV6; 544 if(writeBackStructure.ipv4HeaderPresent || writeBackStructure.ipv6HeaderPresent) 545 { 546 switch(((IpPacket)frame.UnderlyingPacket.PayloadPacket).NextHeader) 547 { 548 case IPProtocolType.UDP: 549 writeBackStructure.payloadType = PayloadType.UDP; 550 break; 551 case IPProtocolType.TCP: 552 writeBackStructure.payloadType = PayloadType.TCP; 553 break; 554 case IPProtocolType.ICMP: 555 case IPProtocolType.ICMPV6: 556 writeBackStructure.payloadType = PayloadType.ICMP; 557 break; 558 case IPProtocolType.IGMP: 559 if(!writeBackStructure.ipv4HeaderPresent) 560 { 561 goto default; 562 } 563 writeBackStructure.payloadType = PayloadType.IGMPIPV4; 564 break; 565 default: 566 writeBackStructure.payloadType = PayloadType.Unknown; 567 break; 568 } 569 } 570 571 // NOTE: VLAN tagging is not supported by PacketDotNet, the `Type` may contain a VLAN tag 572 switch(frame.UnderlyingPacket.Type) 573 { 574 case EthernetPacketType.Arp: 575 writeBackStructure.lengthTypeField = PacketKind.ARPRequest; 576 break; 577 case EthernetPacketType.MacControl: 578 writeBackStructure.lengthTypeField = PacketKind.MACControlPacket; 579 break; 580 case EthernetPacketType.VLanTaggedFrame: 581 writeBackStructure.lengthTypeField = PacketKind.TypePacketWithVLANTag; 582 break; 583 case EthernetPacketType.ProviderBridging: 584 writeBackStructure.lengthTypeField = PacketKind.TypePacketWithDoubleVLANTag; 585 break; 586 case EthernetPacketType.ConnectivityFaultManagementOrOperationsAdministrationManagement: 587 writeBackStructure.lengthTypeField = PacketKind.OAMPacket; 588 break; 589 default: 590 writeBackStructure.lengthTypeField = (uint)frame.UnderlyingPacket.Type < EtherTypeMinimalValue ? PacketKind.LengthPacket : PacketKind.TypePacket; 591 break; 592 } 593 594 writeBackStructure.timestampAvailable = parent.enableTimestamp.Value; 595 writeBackStructure.timestampDropped = false; 596 writeBackStructure.dribbleBitError = false; 597 writeBackStructure.receiveError = false; 598 writeBackStructure.overflowError = false; 599 writeBackStructure.receiveWatchdogTimeout = false; 600 writeBackStructure.giantPacket = false; 601 writeBackStructure.crcError = parent.crcCheckDisable.Value ? false : !EthernetFrame.CheckCRC(bytes); 602 writeBackStructure.errorSummary = new bool[] 603 { 604 writeBackStructure.dribbleBitError, 605 writeBackStructure.receiveError, 606 writeBackStructure.overflowError, 607 writeBackStructure.receiveWatchdogTimeout, 608 writeBackStructure.giantPacket, 609 writeBackStructure.crcError, 610 }.Any(x => x); 611 #if DEBUG 612 this.Log(LogLevel.Noisy, "Receive: Writing {0} to 0x{1:X}.", writeBackStructure, descriptor.Address); 613 #endif 614 descriptor.SetDescriptor(writeBackStructure); 615 descriptor.Write(); 616 IncreaseRxDescriptorPointer(); 617 618 if(!writeBackStructure.lastDescriptor) 619 { 620 continue; 621 } 622 623 if(structure.interruptOnCompletion) 624 { 625 rxInterrupt.Value = true; 626 rxWatchdog.Enabled = false; 627 } 628 else 629 { 630 TriggerRxWatchdog(); 631 } 632 earlyRxInterrupt.Value = false; 633 parent.UpdateRxCounters(frame, writeBackStructure); 634 this.Log(LogLevel.Noisy, "Receive: Frame fully processed."); 635 } 636 if(!parent.rxEnable.Value || !startRx.Value) 637 { 638 rxProcessStopped.Value = true; 639 rxState = DMAState.Stopped; 640 this.Log(LogLevel.Debug, "Receive: Stopping Rx DMA at 0x{0:X}.", rxDescriptorRingCurrent.Value); 641 } 642 else 643 { 644 if(rxFinishedRing) 645 { 646 this.Log(LogLevel.Noisy, "Receive: Descriptor ring is empty."); 647 } 648 rxBufferUnavailable.Value |= rxFinishedRing || incomingFrames.Count != 0; 649 rxState |= DMAState.Suspended; 650 this.Log(LogLevel.Debug, "Receive: Suspending Rx DMA at 0x{0:X}.", rxDescriptorRingCurrent.Value); 651 } 652 parent.UpdateInterrupts(); 653 } 654 StartTx()655 private void StartTx() 656 { 657 if(!parent.txEnable.Value) 658 { 659 txState = DMAState.Stopped; 660 this.Log(LogLevel.Noisy, "Transmission: Tx DMA is not enabled."); 661 return; 662 } 663 if(!startTx.Value) 664 { 665 txState = DMAState.Stopped; 666 this.Log(LogLevel.Noisy, "Transmission: Tx DMA is not started."); 667 return; 668 } 669 if(txState == DMAState.Stopped) 670 { 671 txState |= DMAState.Running; 672 txDescriptorRingCurrent.Value = txDescriptorRingStart.Value; 673 this.Log(LogLevel.Debug, "Transmission: Starting Tx DMA at 0x{0:X}.", txDescriptorRingCurrent.Value); 674 } 675 else 676 { 677 this.Log(LogLevel.Debug, "Transmission: Resuming Tx DMA at 0x{0:X}.", txDescriptorRingCurrent.Value); 678 } 679 680 while(!txFinishedRing && parent.txEnable.Value && startTx.Value) 681 { 682 var descriptor = GetTxDescriptor(); 683 684 if(!descriptor.IsOwnedByDMA.Value) 685 { 686 this.Log(LogLevel.Debug, "Transmission: Loaded descriptor is not owned by DMA."); 687 txProcessStopped.Value = true; 688 txBufferUnavailable.Value = true; 689 txState |= DMAState.Suspended; 690 this.Log(LogLevel.Debug, "Transmission: Suspending Tx DMA at 0x{0:X}.", txDescriptorRingCurrent.Value); 691 break; 692 } 693 txState &= ~DMAState.Suspended; 694 if(descriptor.Type.Is<TxDescriptor.NormalReadDescriptor>()) 695 { 696 var structure = descriptor.GetNormalReadDescriptor(); 697 #if DEBUG 698 this.Log(LogLevel.Noisy, "Transmission: Loaded {0} from 0x{1:X}.", structure, descriptor.Address); 699 #endif 700 if(frameAssembler == null && !structure.firstDescriptor) 701 { 702 this.Log(LogLevel.Warning, "Transmission: Building frame without first descriptor."); 703 break; 704 } 705 else if(frameAssembler != null && structure.firstDescriptor) 706 { 707 this.Log(LogLevel.Warning, "Transmission: Building new frame without clearing last frame."); 708 } 709 710 var buffer = structure.FetchBuffer1OrHeader(parent.Bus, parent.CpuContext); 711 txCurrentBuffer.Value = structure.buffer1OrHeaderAddress; 712 var tsoEnabled = structure.tcpSegmentationEnable && tcpSegmentationEnable.Value; 713 714 MACAddress? sourceAddress = null; 715 switch(structure.sourceAddressControl) 716 { 717 case DescriptorSourceAddressOperation.MACAddressRegister0Insert: 718 case DescriptorSourceAddressOperation.MACAddressRegister0Replace: 719 sourceAddress = parent.MAC0; 720 break; 721 case DescriptorSourceAddressOperation.MACAddressRegister1Insert: 722 case DescriptorSourceAddressOperation.MACAddressRegister1Replace: 723 sourceAddress = parent.MAC1; 724 break; 725 default: 726 sourceAddress = null; 727 break; 728 } 729 730 if(!sourceAddress.HasValue) 731 { 732 switch(parent.sourceAddressOperation.Value) 733 { 734 case RegisterSourceAddressOperation.MACAddressRegister0Insert: 735 case RegisterSourceAddressOperation.MACAddressRegister0Replace: 736 sourceAddress = parent.MAC0; 737 break; 738 case RegisterSourceAddressOperation.MACAddressRegister1Insert: 739 case RegisterSourceAddressOperation.MACAddressRegister1Replace: 740 sourceAddress = parent.MAC1; 741 break; 742 default: 743 this.Log(LogLevel.Error, "Using a reserved value in ETH_MACCR.SARC register."); 744 break; 745 } 746 } 747 748 if(structure.firstDescriptor) 749 { 750 if(tsoEnabled) 751 { 752 frameAssembler = new FrameAssembler( 753 parent, 754 buffer, 755 (uint)maximumSegmentSize.Value, 756 latestTxContext, 757 parent.checksumOffloadEnable.Value, 758 parent.SendFrame, 759 sourceAddress 760 ); 761 buffer = structure.FetchBuffer2OrBuffer1(parent.Bus, parent.CpuContext); 762 txCurrentBuffer.Value = structure.buffer2orBuffer1Address; 763 } 764 else 765 { 766 frameAssembler = new FrameAssembler( 767 parent, 768 structure.crcPadControl, 769 parent.checksumOffloadEnable.Value ? structure.checksumControl : ChecksumOperation.None, 770 parent.SendFrame 771 ); 772 } 773 } 774 if(structure.buffer2Length != 0 && !tsoEnabled) 775 { 776 // Though it's not clearly stated in the documentation, the STM driver 777 // expects buffer2 to be valid even with TSO disabled. In this case, 778 // concatenate two buffers when assembling frame to be sent. 779 frameAssembler.PushPayload(buffer); 780 buffer = structure.FetchBuffer2OrBuffer1(parent.Bus, parent.CpuContext); 781 txCurrentBuffer.Value = structure.buffer2orBuffer1Address; 782 } 783 frameAssembler.PushPayload(buffer); 784 earlyTxInterrupt.Value = true; 785 786 if(!structure.lastDescriptor) 787 { 788 txState |= DMAState.ProcessingIntermediate; 789 var writeBackIntermediateStructure = new TxDescriptor.NormalWriteBackDescriptor(); 790 writeBackIntermediateStructure.owner = DescriptorOwner.Application; 791 #if DEBUG 792 this.Log(LogLevel.Noisy, "Transmission: Writing intermediate {0} to 0x{1:X}.", writeBackIntermediateStructure, descriptor.Address); 793 #endif 794 descriptor.SetDescriptor(writeBackIntermediateStructure); 795 descriptor.Write(); 796 IncreaseTxDescriptorPointer(); 797 continue; 798 } 799 800 frameAssembler.FinalizeAssembly(); 801 frameAssembler = null; 802 803 if((txState & DMAState.ProcessingSecond) == 0 && operateOnSecondPacket.Value) 804 { 805 txState |= DMAState.ProcessingSecond; 806 continue; 807 } 808 809 var writeBackStructure = new TxDescriptor.NormalWriteBackDescriptor(); 810 writeBackStructure.ipHeaderError = false; 811 writeBackStructure.deferredBit = false; 812 writeBackStructure.underflowError = structure.buffer1OrHeaderAddress == 0x0 || structure.headerOrBuffer1Length == 0x0; 813 writeBackStructure.excessiveDeferral = false; 814 writeBackStructure.collisionCount = false; 815 writeBackStructure.excessiveCollision = false; 816 writeBackStructure.lateCollision = false; 817 writeBackStructure.noCarrier = false; 818 writeBackStructure.lossOfCarrier = false; 819 writeBackStructure.payloadChecksumError = false; 820 writeBackStructure.packetFlushed = false; 821 writeBackStructure.jabberTimeout = false; 822 writeBackStructure.errorSummary = new bool[] 823 { 824 writeBackStructure.ipHeaderError, 825 writeBackStructure.jabberTimeout, 826 writeBackStructure.packetFlushed, 827 writeBackStructure.payloadChecksumError, 828 writeBackStructure.lossOfCarrier, 829 writeBackStructure.noCarrier, 830 writeBackStructure.lateCollision, 831 writeBackStructure.excessiveCollision, 832 writeBackStructure.excessiveDeferral, 833 writeBackStructure.underflowError, 834 }.Any(x => x); 835 writeBackStructure.txTimestampCaptured = false; 836 writeBackStructure.owner = DescriptorOwner.Application; 837 writeBackStructure.firstDescriptor = structure.firstDescriptor; 838 writeBackStructure.lastDescriptor = structure.lastDescriptor; 839 840 if(structure.transmitTimestampEnable && parent.enableTimestamp.Value) 841 { 842 this.Log(LogLevel.Error, "Transmission: Timestamping is not supported."); 843 } 844 #if DEBUG 845 this.Log(LogLevel.Noisy, "Transmission: Writing {0} to 0x{1:X}.", writeBackStructure, descriptor.Address); 846 #endif 847 descriptor.SetDescriptor(writeBackStructure); 848 849 if(structure.interruptOnCompletion) 850 { 851 txInterrupt.Value = true; 852 } 853 } 854 else if(descriptor.Type.Is<TxDescriptor.ContextDescriptor>()) 855 { 856 var structure = descriptor.GetContextDescriptor(); 857 latestTxContext = structure; 858 #if DEBUG 859 this.Log(LogLevel.Noisy, "Transmission: Loaded {0} from 0x{1:X}.", structure, descriptor.Address); 860 #endif 861 if(structure.oneStepTimestampCorrectionEnable && structure.oneStepTimestampCorrectionInputOrMaximumSegmentSizeValid) 862 { 863 this.Log(LogLevel.Error, "Transmission: Timestamping is not supported. One Step Timestamp Correction failed."); 864 } 865 structure.owner = DescriptorOwner.Application; 866 #if DEBUG 867 this.Log(LogLevel.Noisy, "Transmission: Writing {0} to 0x{1:X}.", structure, descriptor.Address); 868 #endif 869 descriptor.SetDescriptor(structure); 870 } 871 else 872 { 873 throw new RecoverableException("Unreachable"); 874 } 875 descriptor.Write(); 876 IncreaseTxDescriptorPointer(); 877 } 878 879 if(txFinishedRing) 880 { 881 txBufferUnavailable.Value = true; 882 txState |= DMAState.Suspended; 883 this.Log(LogLevel.Debug, "Transmission: Descriptor ring is empty."); 884 } 885 if(!parent.txEnable.Value || !startTx.Value) 886 { 887 txState = DMAState.Stopped; 888 txProcessStopped.Value = true; 889 this.Log(LogLevel.Debug, "Transmission: Stopping Tx DMA at 0x{0:X}.", txDescriptorRingCurrent.Value); 890 } 891 parent.UpdateInterrupts(); 892 } 893 Log(LogLevel level, string format, params object[] args)894 private void Log(LogLevel level, string format, params object[] args) 895 { 896 parent.Log(level, $"DMA Channel {channelNumber}: {format}", args); 897 } 898 GetNormalInterruptSummary(bool txMask = true, bool rxMask = true)899 private bool GetNormalInterruptSummary(bool txMask = true, bool rxMask = true) 900 { 901 return (txMask && txInterrupt.Value && txInterruptEnable.Value) || 902 (txBufferUnavailable.Value && txBufferUnavailableEnable.Value) || 903 (rxMask && rxInterrupt.Value && rxInterruptEnable.Value) || 904 (earlyRxInterrupt.Value && earlyRxInterruptEnable.Value); 905 } 906 907 private ulong RxBuffer1Size => alternateRxBufferSize.Value == 0 ? rxBufferSize.Value : alternateRxBufferSize.Value; 908 private ulong RxBuffer2Size => rxBufferSize.Value; 909 910 // TODO: Maybe remove those: 911 private ulong ProgrammableBurstLengthMultiplier => programmableBurstLengthTimes8.Value ? 8UL : 1UL; 912 private ulong TxProgrammableBurstLength => txProgrammableBurstLength.Value * ProgrammableBurstLengthMultiplier; 913 private ulong RxProgrammableBurstLength => rxProgrammableBurstLength.Value * ProgrammableBurstLengthMultiplier; 914 915 private IValueRegisterField maximumSegmentSize; 916 private IFlagRegisterField programmableBurstLengthTimes8; 917 private IValueRegisterField descriptorSkipLength; 918 private IFlagRegisterField startTx; 919 private IFlagRegisterField operateOnSecondPacket; 920 private IFlagRegisterField tcpSegmentationEnable; 921 private IValueRegisterField txProgrammableBurstLength; 922 private IFlagRegisterField startRx; 923 private IValueRegisterField rxBufferSize; 924 private IValueRegisterField rxProgrammableBurstLength; 925 private IValueRegisterField txDescriptorRingStart; 926 private IValueRegisterField rxDescriptorRingStart; 927 private IValueRegisterField txDescriptorRingTail; 928 private IValueRegisterField rxDescriptorRingTail; 929 private IValueRegisterField txDescriptorRingLength; 930 private IValueRegisterField rxDescriptorRingLength; 931 private IValueRegisterField alternateRxBufferSize; 932 private IValueRegisterField txDescriptorRingCurrent; 933 private IValueRegisterField rxDescriptorRingCurrent; 934 private IValueRegisterField txCurrentBuffer; 935 private IValueRegisterField rxCurrentBuffer; 936 937 private IFlagRegisterField txInterruptEnable; 938 private IFlagRegisterField txProcessStoppedEnable; 939 private IFlagRegisterField txBufferUnavailableEnable; 940 private IFlagRegisterField rxInterruptEnable; 941 private IFlagRegisterField rxBufferUnavailableEnable; 942 private IFlagRegisterField rxProcessStoppedEnable; 943 private IFlagRegisterField rxWatchdogTimeoutEnable; 944 private IFlagRegisterField earlyTxInterruptEnable; 945 private IFlagRegisterField earlyRxInterruptEnable; 946 private IFlagRegisterField fatalBusErrorEnable; 947 private IFlagRegisterField contextDescriptorErrorEnable; 948 private IFlagRegisterField abnormalInterruptSummaryEnable; 949 private IValueRegisterField rxWatchdogCounter; 950 private IValueRegisterField rxWatchdogCounterUnit; 951 private IFlagRegisterField normalInterruptSummaryEnable; 952 private IFlagRegisterField txInterrupt; 953 private IFlagRegisterField txProcessStopped; 954 private IFlagRegisterField txBufferUnavailable; 955 private IFlagRegisterField rxInterrupt; 956 private IFlagRegisterField rxBufferUnavailable; 957 private IFlagRegisterField rxProcessStopped; 958 private IFlagRegisterField rxWatchdogTimeout; 959 private IFlagRegisterField earlyTxInterrupt; 960 private IFlagRegisterField earlyRxInterrupt; 961 private IFlagRegisterField fatalBusError; 962 private IFlagRegisterField contextDescriptorError; 963 private IFlagRegisterField abnormalInterruptSummary; 964 private IFlagRegisterField normalInterruptSummary; 965 966 private FrameAssembler frameAssembler; 967 968 private bool rxFinishedRing = true; 969 private bool txFinishedRing = true; 970 private DMAState txState = DMAState.Stopped; 971 private DMAState rxState = DMAState.Stopped; 972 private ulong rxOffset; 973 private TxDescriptor.ContextDescriptor? latestTxContext; 974 private int rxQueueLength; 975 976 private readonly Queue<EthernetFrame> incomingFrames; 977 private readonly LimitTimer rxWatchdog; 978 979 private readonly SynopsysDWCEthernetQualityOfService parent; 980 private readonly int channelNumber; 981 private readonly bool hasInterrupts; 982 } 983 } 984 }