30 static constexpr bool DebugEthernet =
false;
35 static constexpr bool DebugDroppedFrames =
true;
40 static constexpr uint16_t MaxFrameSize = 1500;
45 using Debug = ConditionalDebug<DebugEthernet,
"Ethernet driver">;
50 using DebugFrameDrops =
51 ConditionalDebug<DebugDroppedFrames,
"Ethernet driver">;
62 enum class SpiCommand : uint8_t
77 enum class RegisterOffset : uint8_t
79 ChipConfiguration = 0x08,
81 MacAdressMiddle = 0x12,
82 MacAddressHigh = 0x14,
83 OnChipBusControl = 0x20,
85 MemoryBistInfo = 0x24,
90 TransmitControl = 0x70,
91 TransmitStatus = 0x72,
92 ReceiveControl1 = 0x74,
93 ReceiveControl2 = 0x76,
94 TransmitQueueMemoryInfo = 0x78,
95 ReceiveFrameHeaderStatus = 0x7C,
96 ReceiveFrameHeaderByteCount = 0x7E,
97 TransmitQueueCommand = 0x80,
98 ReceiveQueueCommand = 0x82,
99 TransmitFrameDataPointer = 0x84,
100 ReceiveFrameDataPointer = 0x86,
101 ReceiveDurationTimerThreshold = 0x8C,
102 ReceiveDataByteCountThreshold = 0x8E,
103 InterruptEnable = 0x90,
104 InterruptStatus = 0x92,
105 ReceiveFrameCountThreshold = 0x9c,
106 TransmitNextTotalFrameSize = 0x9E,
110 FlowControlLowWatermark = 0xB0,
111 FlowControlHighWatermark = 0xB2,
112 FlowControlOverrunWatermark = 0xB4,
114 ChipGlobalControl = 0xC6,
115 IndirectAccessControl = 0xC8,
116 IndirectAccessDataLow = 0xD0,
117 IndirectAccessDataHigh = 0xD2,
118 PowerManagementEventControl = 0xD4,
119 GoSleepWakeUp = 0xD6,
121 Phy1MiiBasicControl = 0xE4,
122 Phy1MiiBasicStatus = 0xE6,
125 Phy1AutoNegotiationAdvertisement = 0xEC,
126 Phy1AutoNegotiationLinkPartnerAbility = 0xEE,
127 Phy1SpecialControlStatus = 0xF4,
132 using MACAddress = std::array<uint8_t, 6>;
137 enum [[clang::flag_enum]] TransmitControl : uint16_t
139 TransmitEnable = 1 << 0,
140 TransmitCrcEnable = 1 << 1,
141 TransmitPaddingEnable = 1 << 2,
142 TransmitFlowControlEnable = 1 << 3,
143 FlushTransmitQueue = 1 << 4,
144 TransmitChecksumGenerationIp = 1 << 5,
145 TransmitChecksumGenerationTcp = 1 << 6,
146 TransmitChecksumGenerationIcmp = 1 << 8,
152 enum [[clang::flag_enum]] ReceiveControl1 : uint16_t
154 ReceiveEnable = 1 << 0,
155 ReceiveInverseFilter = 1 << 1,
156 ReceiveAllEnable = 1 << 4,
157 ReceiveUnicastEnable = 1 << 5,
158 ReceiveMulticastEnable = 1 << 6,
159 ReceiveBroadcastEnable = 1 << 7,
160 ReceiveMulticastAddressFilteringWithMacAddressEnable = 1 << 8,
161 ReceiveErrorFrameEnable = 1 << 9,
162 ReceiveFlowControlEnable = 1 << 10,
163 ReceivePhysicalAddressFilteringWithMacAddressEnable = 1 << 11,
164 ReceiveIpFrameChecksumCheckEnable = 1 << 12,
165 ReceiveTcpFrameChecksumCheckEnable = 1 << 13,
166 ReceiveUdpFrameChecksumCheckEnable = 1 << 14,
167 FlushReceiveQueue = 1 << 15,
173 enum [[clang::flag_enum]] ReceiveControl2 : uint16_t
175 ReceiveSourceAddressFiltering = 1 << 0,
176 ReceiveIcmpFrameChecksumEnable = 1 << 1,
177 UdpLiteFrameEnable = 1 << 2,
178 ReceiveIpv4Ipv6UdpFrameChecksumEqualZero = 1 << 3,
179 ReceiveIpv4Ipv6FragmentFramePass = 1 << 4,
180 DataBurst4Bytes = 0b000 << 5,
181 DataBurst8Bytes = 0b001 << 5,
182 DataBurst16Bytes = 0b010 << 5,
183 DataBurst32Bytes = 0b011 << 5,
184 DataBurstSingleFrame = 0b100 << 5,
190 enum [[clang::flag_enum]] ReceiveFrameHeaderStatus : uint16_t
192 ReceiveCrcError = 1 << 0,
193 ReceiveRuntFrame = 1 << 1,
194 ReceiveFrameTooLong = 1 << 2,
195 ReceiveFrameType = 1 << 3,
196 ReceiveMiiError = 1 << 4,
197 ReceiveUnicastFrame = 1 << 5,
198 ReceiveMulticastFrame = 1 << 6,
199 ReceiveBroadcastFrame = 1 << 7,
200 ReceiveUdpFrameChecksumStatus = 1 << 10,
201 ReceiveTcpFrameChecksumStatus = 1 << 11,
202 ReceiveIpFrameChecksumStatus = 1 << 12,
203 ReceiveIcmpFrameChecksumStatus = 1 << 13,
204 ReceiveFrameValid = 1 << 15,
210 enum [[clang::flag_enum]] ReceiveQueueCommand : uint16_t
212 ReleaseReceiveErrorFrame = 1 << 0,
213 StartDmaAccess = 1 << 3,
214 AutoDequeueReceiveQueueFrameEnable = 1 << 4,
215 ReceiveFrameCountThresholdEnable = 1 << 5,
216 ReceiveDataByteCountThresholdEnable = 1 << 6,
217 ReceiveDurationTimerThresholdEnable = 1 << 7,
218 ReceiveIpHeaderTwoByteOffsetEnable = 1 << 9,
219 ReceiveFrameCountThresholdStatus = 1 << 10,
220 ReceiveDataByteCountThresholdstatus = 1 << 11,
221 ReceiveDurationTimerThresholdStatus = 1 << 12,
227 enum [[clang::flag_enum]] TransmitQueueCommand : uint16_t
229 ManualEnqueueTransmitQueueFrameEnable = 1 << 0,
230 TransmitQueueMemoryAvailableMonitor = 1 << 1,
231 AutoEnqueueTransmitQueueFrameEnable = 1 << 2,
238 enum [[clang::flag_enum]] FrameDataPointer : uint16_t
244 FrameDataPointerAutoIncrement = 1 << 14,
250 enum [[clang::flag_enum]] Interrupt : uint16_t
252 EnergyDetectInterrupt = 1 << 2,
253 LinkupDetectInterrupt = 1 << 3,
254 ReceiveMagicPacketDetectInterrupt = 1 << 4,
255 ReceiveWakeupFrameDetectInterrupt = 1 << 5,
256 TransmitSpaceAvailableInterrupt = 1 << 6,
257 ReceiveProcessStoppedInterrupt = 1 << 7,
258 TransmitProcessStoppedInterrupt = 1 << 8,
259 ReceiveOverrunInterrupt = 1 << 11,
260 ReceiveInterrupt = 1 << 13,
261 TransmitInterrupt = 1 << 14,
262 LinkChangeInterruptStatus = 1 << 15,
268 enum [[clang::flag_enum]] PowerManagementEventControl : uint16_t
270 PowerManagementModeNormal = 0b00 << 0,
271 PowerManagementModeEnergyDetect = 0b01 << 0,
272 PowerManagementModeReserved = 0b10 << 0,
273 PowerManagementModePowerSaving = 0b11 << 0,
274 PowerManagementModeMask = 0b11 << 0,
276 WakeUpEventEnergy = 0b0001 << 2,
277 WakeUpEventLinkup = 0b0010 << 2,
278 WakeUpEventMagic = 0b0100 << 2,
279 WakeUpEventFrame = 0b1000 << 2,
280 WakeUpEventMask = 0b1111 << 2,
282 WakeUpToNormal = 1 << 6,
283 AutoWakeEnable = 1 << 7,
285 WakeOnLanEventPinEnergy = 0b0001 << 8,
286 WakeOnLanEventPinLinkup = 0b0010 << 8,
287 WakeOnLanEventPinMagic = 0b0100 << 8,
288 WakeOnLanEventPinFrame = 0b1000 << 8,
289 WakeOnLanEventPinMask = 0b1111 << 8,
291 WakeOnLanEventPinPolarity = 1 << 12,
292 WakeOnLanEventPinDelay = 1 << 14
298 enum [[clang::flag_enum]] Port1Control : uint16_t
300 Advertised10BTHalfDuplexCapability = 1 << 0,
301 Advertised10BTFullDuplexCapability = 1 << 1,
302 Advertised100BTHalfDuplexCapability = 1 << 2,
303 Advertised100BTFullDuplexCapability = 1 << 3,
304 AdvertisedFlowControlCapability = 1 << 4,
305 ForceDuplex = 1 << 5,
307 AutoNegotiationEnable = 1 << 7,
309 DisableAutoMDIMDIX = 1 << 10,
310 RestartAutoNegotiation = 1 << 13,
311 TransmitterDisable = 1 << 14,
318 enum [[clang::flag_enum]] Port1Status : uint16_t
320 Partner10BTHalfDuplexCapability = 1 << 0,
321 Partner10BTFullDuplexCapability = 1 << 1,
322 Partner100BTHalfDuplexCapability = 1 << 2,
323 Partner100BTFullDuplexCapability = 1 << 3,
324 PartnerFlowControlCapability = 1 << 4,
326 AutoNegotiationDone = 1 << 6,
328 OperationDuplex = 1 << 9,
329 OperationSpeed = 1 << 10,
330 PolarityReverse = 1 << 13,
338 const uint32_t *receiveInterruptFutex;
343 [[nodiscard]] uint16_t register_read(RegisterOffset reg)
const
365 uint8_t addr =
static_cast<uint8_t
>(reg);
366 uint8_t byteEnable = (addr & 0x2) == 0 ? 0b0011 : 0b1100;
368 bytes[0] = (
static_cast<uint8_t
>(SpiCommand::ReadRegister) << 6) |
369 (byteEnable << 2) | (addr >> 6);
370 bytes[1] = (addr << 2) & 0b11110000;
372 spi()->chip_select_assert(
true);
373 spi()->blocking_write(bytes,
sizeof(bytes));
375 spi()->blocking_read(
reinterpret_cast<uint8_t *
>(&val),
sizeof(val));
376 spi()->chip_select_assert(
false);
383 void register_write(RegisterOffset reg, uint16_t val)
const
386 uint8_t addr =
static_cast<uint8_t
>(reg);
387 uint8_t byteEnable = (addr & 0x2) == 0 ? 0b0011 : 0b1100;
389 bytes[0] = (
static_cast<uint8_t
>(SpiCommand::WriteRegister) << 6) |
390 (byteEnable << 2) | (addr >> 6);
391 bytes[1] = (addr << 2) & 0b11110000;
393 spi()->chip_select_assert(
true);
394 spi()->blocking_write(bytes,
sizeof(bytes));
395 spi()->blocking_write(
reinterpret_cast<uint8_t *
>(&val),
sizeof(val));
397 spi()->chip_select_assert(
false);
403 void register_set(RegisterOffset reg, uint16_t mask)
const
405 uint16_t old = register_read(reg);
406 register_write(reg, old | mask);
412 void register_clear(RegisterOffset reg, uint16_t mask)
const
414 uint16_t old = register_read(reg);
415 register_write(reg, old & ~mask);
422 gnu::always_inline]] Capability<volatile SonataSpi::EthernetMac>
431 uint16_t framesToProcess = 0;
441 std::unique_ptr<uint8_t[]> transmitBuffer;
453 FlagLockPriorityInherited chipSelectLock;
458 std::unique_ptr<uint8_t[]> receiveBuffer;
466 transmitBuffer = std::make_unique<uint8_t[]>(MaxFrameSize);
467 receiveBuffer = std::make_unique<uint8_t[]>(MaxFrameSize);
470 spi()->reset_assert(
true);
472 spi()->reset_assert(
false);
474 uint16_t chipId = register_read(RegisterOffset::ChipIdEnable);
475 Debug::log(
"Chip ID is {}", chipId);
478 Debug::Assert((chipId & 0xFFF0) == 0x8870,
"Unexpected Chip ID");
482 register_write(RegisterOffset::TransmitFrameDataPointer,
483 FrameDataPointer::FrameDataPointerAutoIncrement);
484 register_write(RegisterOffset::TransmitControl,
485 TransmitControl::TransmitCrcEnable |
486 TransmitControl::TransmitPaddingEnable |
487 TransmitControl::TransmitFlowControlEnable |
488 TransmitControl::TransmitChecksumGenerationIp |
489 TransmitControl::TransmitChecksumGenerationTcp |
490 TransmitControl::TransmitChecksumGenerationIcmp);
491 register_write(RegisterOffset::ReceiveFrameDataPointer,
492 FrameDataPointer::FrameDataPointerAutoIncrement);
494 register_write(RegisterOffset::ReceiveFrameCountThreshold, 0x0001);
495 register_write(RegisterOffset::ReceiveControl1,
496 ReceiveControl1::ReceiveUnicastEnable |
497 ReceiveControl1::ReceiveMulticastEnable |
498 ReceiveControl1::ReceiveBroadcastEnable |
499 ReceiveControl1::ReceiveFlowControlEnable |
501 ReceivePhysicalAddressFilteringWithMacAddressEnable |
502 ReceiveControl1::ReceiveIpFrameChecksumCheckEnable |
503 ReceiveControl1::ReceiveTcpFrameChecksumCheckEnable |
504 ReceiveControl1::ReceiveUdpFrameChecksumCheckEnable);
511 RegisterOffset::ReceiveControl2,
512 ReceiveControl2::UdpLiteFrameEnable |
513 ReceiveControl2::ReceiveIpv4Ipv6UdpFrameChecksumEqualZero |
514 ReceiveControl2::ReceiveIpv4Ipv6FragmentFramePass |
515 ReceiveControl2::DataBurstSingleFrame);
517 RegisterOffset::ReceiveQueueCommand,
518 ReceiveQueueCommand::ReceiveFrameCountThresholdEnable |
519 ReceiveQueueCommand::AutoDequeueReceiveQueueFrameEnable);
525 register_set(RegisterOffset::Port1Control,
526 Port1Control::RestartAutoNegotiation);
530 register_write(RegisterOffset::FlowControlLowWatermark, 0x0600);
533 register_write(RegisterOffset::FlowControlHighWatermark, 0x0400);
536 register_write(RegisterOffset::InterruptStatus, 0xFFFF);
537 receiveInterruptFutex =
540 register_write(RegisterOffset::InterruptEnable,
541 LinkupDetectInterrupt | ReceiveInterrupt);
544 register_set(RegisterOffset::TransmitControl,
545 TransmitControl::TransmitEnable);
547 register_set(RegisterOffset::ReceiveControl1,
548 ReceiveControl1::ReceiveEnable);
564 static constexpr MACAddress mac_address_default()
566 return {0x3a, 0x30, 0x25, 0x24, 0xfe, 0x7a};
569 void mac_address_set(MACAddress address = mac_address_default())
571 register_write(RegisterOffset::MacAddressHigh,
572 (address[0] << 8) | address[1]);
573 register_write(RegisterOffset::MacAdressMiddle,
574 (address[2] << 8) | address[3]);
575 register_write(RegisterOffset::MacAddressLow,
576 (address[4] << 8) | address[5]);
579 uint32_t receive_interrupt_value()
581 return *receiveInterruptFutex;
584 int receive_interrupt_complete(
Timeout *timeout,
585 uint32_t lastInterruptValue)
599 if (*receiveInterruptFutex == lastInterruptValue)
601 Debug::log(
"Acknowledged interrupt, sleeping on futex {}",
602 receiveInterruptFutex);
604 timeout, receiveInterruptFutex, lastInterruptValue);
606 Debug::log(
"Scheduler announces interrupt has fired");
617 Capability<uint8_t> buffer;
620 friend class Ksz8851Ethernet;
624 Capability<uint8_t> buffer,
626 : guard(std::move(guard)), buffer(buffer), length(length)
636 uint16_t status = register_read(RegisterOffset::Port1Status);
637 return (status & Port1Status::LinkGood) != 0;
640 std::optional<Frame> receive_frame()
643 if (framesToProcess == 0)
645 uint16_t isr = register_read(RegisterOffset::InterruptStatus);
647 if (isr & LinkupDetectInterrupt)
650 register_set(RegisterOffset::PowerManagementEventControl,
651 PowerManagementEventControl::WakeUpEventLinkup);
654 if (!(isr & ReceiveInterrupt))
660 register_write(RegisterOffset::InterruptStatus, ReceiveInterrupt);
665 register_read(RegisterOffset::ReceiveFrameCountThreshold) >> 8;
669 for (; framesToProcess; framesToProcess--)
672 register_read(RegisterOffset::ReceiveFrameHeaderStatus);
674 register_read(RegisterOffset::ReceiveFrameHeaderByteCount) &
677 (status & ReceiveFrameValid) &&
679 (ReceiveCrcError | ReceiveRuntFrame | ReceiveFrameTooLong |
680 ReceiveMiiError | ReceiveUdpFrameChecksumStatus |
681 ReceiveTcpFrameChecksumStatus | ReceiveIpFrameChecksumStatus |
682 ReceiveIcmpFrameChecksumStatus));
686 DebugFrameDrops::log(
"Dropping frame with status: {}", status);
694 DebugFrameDrops::log(
"Dropping frame with zero length");
702 uint16_t paddedLength = (length + 3) & ~0x3;
703 if (paddedLength > MaxFrameSize)
705 DebugFrameDrops::log(
"Dropping frame that is too large: {}",
712 Debug::log(
"Receiving frame of length {}", length);
714 LockGuard guard{receiveBufferMutex};
718 register_write(RegisterOffset::ReceiveFrameDataPointer,
719 FrameDataPointer::FrameDataPointerAutoIncrement);
720 register_set(RegisterOffset::ReceiveQueueCommand, StartDmaAccess);
723 uint8_t cmd =
static_cast<uint8_t
>(SpiCommand::ReadDma) << 6;
724 spi()->chip_select_assert(
true);
725 spi()->blocking_write(&cmd, 1);
730 spi()->blocking_read(dummy,
sizeof(dummy));
732 spi()->blocking_read(receiveBuffer.get(), paddedLength);
734 spi()->chip_select_assert(
false);
736 register_clear(RegisterOffset::ReceiveQueueCommand, StartDmaAccess);
737 framesToProcess -= 1;
739 Capability<uint8_t> boundedBuffer{receiveBuffer.get()};
740 boundedBuffer.bounds().set_inexact(length);
743 boundedBuffer.permissions() &=
744 CHERI::PermissionSet{CHERI::Permission::Load};
746 return Frame{std::move(guard), boundedBuffer, length};
760 bool send_frame(
const uint8_t *buffer, uint16_t length,
auto &&check)
763 uint16_t paddedLength = (length + 3) & ~0x3;
764 if (paddedLength > MaxFrameSize)
766 Debug::log(
"Frame size {} is larger than the maximum size", length);
784 memcpy(transmitBuffer.get(), buffer, length);
785 if (!check(transmitBuffer.get(), length))
794 while ((register_read(RegisterOffset::TransmitQueueMemoryInfo) &
799 Debug::log(
"Sending frame of length {}", length);
802 register_set(RegisterOffset::ReceiveQueueCommand, StartDmaAccess);
805 uint8_t cmd =
static_cast<uint8_t
>(SpiCommand::WriteDma) << 6;
806 spi()->chip_select_assert(
true);
807 spi()->blocking_write(&cmd, 1);
809 uint32_t header =
static_cast<uint32_t
>(length) << 16;
810 spi()->blocking_write(
reinterpret_cast<uint8_t *
>(&header),
813 spi()->blocking_write(transmitBuffer.get(), paddedLength);
816 spi()->chip_select_assert(
false);
819 register_clear(RegisterOffset::ReceiveQueueCommand, StartDmaAccess);
823 RegisterOffset::TransmitQueueCommand,
824 TransmitQueueCommand::ManualEnqueueTransmitQueueFrameEnable);
830 void drop_error_frame()
832 register_set(RegisterOffset::ReceiveQueueCommand,
833 ReleaseReceiveErrorFrame);
836 while (register_read(RegisterOffset::ReceiveQueueCommand) &
837 ReleaseReceiveErrorFrame)