32 static constexpr bool DebugEthernet =
false;
37 static constexpr bool DebugDroppedFrames =
false;
42 using Debug = ConditionalDebug<DebugEthernet,
"Ethernet driver">;
53 enum class RegisterOffset :
size_t
102 TransmitFrameLengthPing = 0x20,
106 TransmitControlPing = 0x24,
110 TransmitFrameLengthPong = 0x28,
114 TransmitControlPong = 0x2c,
118 ReceiveControlPing = 0x30,
122 ReceiveControlPong = 0x34,
127 GlobalInterruptEnable = 0x38,
134 InterruptStatus = 0x3c,
139 ReceiveFrameLength = 0x40,
143 ReceivedFramesCount = 0x44,
147 ReceivedFramesPassedToSoftware = 0x48,
152 ReceiveDroppedFramesBuffersFull = 0x4c,
157 ReceiveDroppedFramesFCSFailed = 0x50,
162 ReceiveDroppedFramesInvalidAddress = 0x54,
165 using MACAddress = std::array<uint8_t, 6>;
170 enum class FilterMode : uint32_t
175 EnableAddressFiltering = 1 << 13,
179 DropInvalidCRC = 1 << 12,
183 AllowIPv6Multicast = 1 << 11,
187 AllowIPv4Multicast = 1 << 10,
191 AllowBroadcast = 1 << 9,
195 AllowUnicast = 1 << 8,
202 const uint32_t *receiveInterruptFutex;
208 struct DroppedFrameCount
213 uint32_t droppedFrameCount[3];
217 template<RegisterOffset Reg>
220 uint32_t &get<RegisterOffset::ReceiveDroppedFramesBuffersFull>()
222 return droppedFrameCount[0];
226 uint32_t &get<RegisterOffset::ReceiveDroppedFramesFCSFailed>()
228 return droppedFrameCount[1];
232 uint32_t &get<RegisterOffset::ReceiveDroppedFramesInvalidAddress>()
234 return droppedFrameCount[2];
250 [[no_unique_address]] std::
251 conditional_t<DebugDroppedFrames, DroppedFrameCount, Empty> droppedFrames;
257 template<RegisterOffset Reg,
typename T = decltype(droppedFrames)>
258 void dropped_frames_log_if_changed(T &droppedFrames)
260 if constexpr (std::is_same_v<T, DroppedFrameCount>)
262 auto &lastCount = droppedFrames.template get<Reg>();
263 auto count = mmio_register<Reg>();
264 if (count != lastCount)
266 ConditionalDebug<
true,
"Ethernet driver">::log(
267 "Dropped frames in counter {}: {}", Reg, count);
277 bool filter_mode_update(FilterMode mode,
bool enable)
279 auto &macControl = mmio_register<RegisterOffset::MACControl>();
280 uint32_t modeBit =
static_cast<uint32_t
>(mode);
281 uint32_t oldMode = macControl;
282 Debug::log(
"Old filter mode {}: {}", mode, oldMode);
285 macControl = oldMode | modeBit;
289 macControl = oldMode & ~modeBit;
291 return oldMode | modeBit;
297 enum class PHYRegister
299 BasicControlRegister = 0,
300 BasicStatusRegister = 1,
303 AutoNegotiationAdvertisement = 4,
304 AutoNegotiationLinkPartnerAbility = 5,
313 bool receiveBufferInUse[2] = {
false,
false};
314 bool sendBufferInUse[2] = {
false,
false};
316 BufferID nextReceiveBuffer = BufferID::Ping;
318 constexpr static BufferID next_buffer_id(BufferID current)
320 return current == BufferID::Ping ? BufferID::Pong : BufferID::Ping;
328 auto &macControl = mmio_register<RegisterOffset::MACControl>();
333 mmio_register<RegisterOffset::MDIOControl>() = 0x10;
341 [[nodiscard]] __always_inline Capability<volatile uint32_t>
351 template<RegisterOffset Offset>
352 [[nodiscard]]
volatile uint32_t &mmio_register()
const
354 auto reg = mmio_region();
355 reg.address() +=
static_cast<size_t>(Offset);
356 reg.bounds() =
sizeof(uint32_t);
367 void mdio_wait_for_ready()
369 auto &mdioControl = mmio_register<RegisterOffset::MDIOControl>();
370 while (mdioControl & 1)
382 void mdio_start_transaction()
384 auto &mdioControl = mmio_register<RegisterOffset::MDIOControl>();
385 Debug::Assert(((mdioControl & ((1 << 3) | 1)) == 0),
"MDIO is busy");
387 mdioControl = (1 << 3) | 1;
394 uint8_t *receive_buffer_pointer(BufferID index = BufferID::Ping)
396 auto buffer = mmio_region();
398 static_cast<size_t>(index == BufferID::Ping ? 0x2000 : 0x2800);
399 buffer.bounds() = 0x800;
400 return const_cast<uint8_t *
>(
401 reinterpret_cast<volatile uint8_t *
>((buffer.get())));
408 uint8_t *transmit_buffer_pointer(BufferID index = BufferID::Ping)
410 auto buffer = mmio_region();
412 static_cast<size_t>(index == BufferID::Ping ? 0x1000 : 0x1800);
413 buffer.bounds() = 0x800;
414 return const_cast<uint8_t *
>(
415 reinterpret_cast<volatile uint8_t *
>((buffer.get())));
422 mdio_write(uint8_t phyAddress, PHYRegister registerAddress, uint16_t data)
424 mdio_wait_for_ready();
425 auto &mdioAddress = mmio_register<RegisterOffset::MDIOAddress>();
426 auto &mdioWrite = mmio_register<RegisterOffset::MDIODataWrite>();
427 uint32_t writeCommand = (0 << 10) | (phyAddress << 5) |
428 static_cast<uint32_t
>(registerAddress);
429 mdioAddress = writeCommand;
431 mdio_start_transaction();
437 uint16_t mdio_read(uint8_t phyAddress, PHYRegister registerAddress)
439 mdio_wait_for_ready();
440 auto &mdioAddress = mmio_register<RegisterOffset::MDIOAddress>();
441 uint32_t readCommand =
442 (1 << 10) | (phyAddress << 5) |
static_cast<uint8_t
>(registerAddress);
443 mdioAddress = readCommand;
444 mdio_start_transaction();
445 mdio_wait_for_ready();
446 return mmio_register<RegisterOffset::MDIODataRead>();
460 [&]() {
return mdio_read(1, PHYRegister::Identifier1) == 0x2000; },
461 "PHY identifier 1 is not 0x2000");
464 return (mdio_read(1, PHYRegister::Identifier2) & 0xFFF0) ==
467 "PHY identifier 1 is not 0x5c9x");
469 filter_mode_update(FilterMode::DropInvalidCRC,
true);
470 filter_mode_update(FilterMode::EnableAddressFiltering,
false);
471 filter_mode_update(FilterMode::AllowUnicast,
false);
472 filter_mode_update(FilterMode::AllowIPv4Multicast,
false);
473 filter_mode_update(FilterMode::AllowIPv6Multicast,
false);
474 receiveInterruptFutex =
477 mmio_register<RegisterOffset::GlobalInterruptEnable>() = 0b10;
479 mmio_register<RegisterOffset::InterruptStatus>() = 0b10;
495 static constexpr MACAddress mac_address_default()
497 return {0x60, 0x6A, 0x6A, 0x37, 0x47, 0x88};
500 void mac_address_set(MACAddress address = mac_address_default())
502 auto &macAddressHigh = mmio_register<RegisterOffset::MACAddressHigh>();
503 auto &macAddressLow = mmio_register<RegisterOffset::MACAddressLow>();
504 macAddressHigh = (address[2] << 24) | (address[3] << 16) |
505 (address[4] << 8) | address[5];
506 macAddressLow = (address[1] << 8) | address[0];
509 uint32_t receive_interrupt_value()
511 return *receiveInterruptFutex;
514 int receive_interrupt_complete(
Timeout *timeout,
515 uint32_t lastInterruptValue)
518 auto &interruptStatus =
519 mmio_register<RegisterOffset::InterruptStatus>();
520 interruptStatus = 0b10;
526 if (check_frame(BufferID::Ping) || check_frame(BufferID::Pong))
528 Debug::log(
"Packets already ready, not waiting for interrupt");
533 if (*receiveInterruptFutex == lastInterruptValue)
535 Debug::log(
"Acknowledged interrupt, sleeping on futex {}",
536 receiveInterruptFutex);
538 timeout, receiveInterruptFutex, lastInterruptValue);
540 Debug::log(
"Scheduler announces interrupt has fired");
551 Debug::log(
"Starting autonegotiation");
553 mdio_write(phyAddress,
554 PHYRegister::AutoNegotiationAdvertisement,
555 (1 << 5) | (1 << 6) | 1);
558 phyAddress, PHYRegister::BasicControlRegister, (1 << 12) | (1 << 9));
559 Debug::log(
"Waiting for autonegotiation to complete");
561 while ((mdio_read(phyAddress, PHYRegister::BasicStatusRegister) &
564 if ((loops++ & 0xfffff) == 0)
567 "Waiting for autonegotiation to complete ({} loops): status: "
570 mdio_read(phyAddress, PHYRegister::BasicStatusRegister));
576 return (mdio_read(phyAddress, PHYRegister::BasicStatusRegister) &
579 "Autonegotiation completed but link is down");
580 Debug::log(
"Autonegotiation complete, status: {}",
581 mdio_read(phyAddress, PHYRegister::BasicStatusRegister));
583 mmio_register<RegisterOffset::ReceiveControlPing>() = 1;
584 mmio_register<RegisterOffset::ReceiveControlPong>() = 1;
592 return (mdio_read(1, PHYRegister::BasicStatusRegister) & (1 << 2)) != 0;
595 std::optional<uint16_t> check_frame(BufferID index = BufferID::Ping)
598 auto receiveControl =
599 index == BufferID::Ping
600 ? mmio_register<RegisterOffset::ReceiveControlPing>()
601 : mmio_register<RegisterOffset::ReceiveControlPong>();
602 if ((receiveControl & 1) == 0)
606 Debug::log(
"Buffer has a frame. Error? {}", receiveControl & 2);
607 Debug::log(
"Buffer length: {}", receiveControl >> 16);
608 return {receiveControl >> 16};
611 void complete_receive(BufferID index = BufferID::Ping)
613 Debug::log(
"Completing receive in buffer {}", index);
615 receiveBufferInUse[index] =
false;
616 if (index == BufferID::Ping)
618 mmio_register<RegisterOffset::ReceiveControlPing>() = 1;
622 mmio_register<RegisterOffset::ReceiveControlPong>() = 1;
633 friend class KunyanEthernet;
634 KunyanEthernet ðernetAdaptor;
635 BufferID owningBuffer;
638 BufferedFrame(KunyanEthernet ðernetAdaptor,
639 BufferID owningBuffer,
640 Capability<uint8_t> buffer,
643 : ethernetAdaptor(ethernetAdaptor),
644 owningBuffer(owningBuffer),
649 ethernetAdaptor.receiveBufferInUse[owningBuffer] =
true;
650 if (!ethernetAdaptor.receiveBufferInUse[next_buffer_id(
651 ethernetAdaptor.nextReceiveBuffer)])
653 ethernetAdaptor.nextReceiveBuffer =
654 next_buffer_id(ethernetAdaptor.nextReceiveBuffer);
660 Capability<uint8_t> buffer;
661 BufferedFrame(
const BufferedFrame &) =
delete;
662 BufferedFrame(BufferedFrame &&other)
663 : ethernetAdaptor(other.ethernetAdaptor),
664 owningBuffer(other.owningBuffer),
665 buffer(other.buffer),
668 other.buffer =
nullptr;
673 if (buffer !=
nullptr)
675 ethernetAdaptor.complete_receive(owningBuffer);
680 std::optional<BufferedFrame> receive_frame()
686 if (receiveBufferInUse[nextReceiveBuffer])
688 if (!receiveBufferInUse[next_buffer_id(nextReceiveBuffer)])
691 nextReceiveBuffer = next_buffer_id(nextReceiveBuffer);
700 auto maybeLength = check_frame(nextReceiveBuffer);
708 if (!receiveBufferInUse[next_buffer_id(nextReceiveBuffer)])
712 nextReceiveBuffer = next_buffer_id(nextReceiveBuffer);
713 maybeLength = check_frame(nextReceiveBuffer);
724 auto length = *maybeLength;
727 auto buffer = receive_buffer_pointer(nextReceiveBuffer);
728 Capability<uint8_t> boundedBuffer{buffer};
729 boundedBuffer.bounds() = length;
732 boundedBuffer.permissions() &=
733 CHERI::PermissionSet{CHERI::Permission::Load};
734 Debug::log(
"Received frame from buffer {}", nextReceiveBuffer);
735 return {{*
this, nextReceiveBuffer, buffer, length}};
747 bool send_frame(
const uint8_t *buffer, uint16_t length,
auto &&check)
749 auto &transmitControl =
750 mmio_register<RegisterOffset::TransmitControlPing>();
752 while (transmitControl & 1)
756 auto transmitBuffer = transmit_buffer_pointer();
768 memcpy(transmitBuffer, buffer, length);
769 if (!check(transmitBuffer, length))
778 memset(transmitBuffer + length, 0, 60 - length);
782 mmio_register<RegisterOffset::TransmitFrameLengthPing>() = length;
785 Debug::log(
"Sent frame, waiting for completion");
786 while (transmitControl & 1)
790 Debug::log(
"Transmit control register: {}", transmitControl);
791 if ((transmitControl & 2) != 0)
793 Debug::log(
"Error sending frame");
795 return (transmitControl & 2) == 0;
804 if constexpr (DebugDroppedFrames)
806 dropped_frames_log_if_changed<
807 RegisterOffset::ReceiveDroppedFramesBuffersFull>(droppedFrames);
808 dropped_frames_log_if_changed<
809 RegisterOffset::ReceiveDroppedFramesFCSFailed>(droppedFrames);
810 dropped_frames_log_if_changed<
811 RegisterOffset::ReceiveDroppedFramesInvalidAddress>(
816 void received_frames_log()
818 auto count = mmio_register<RegisterOffset::ReceivedFramesCount>();
819 ConditionalDebug<
true,
"Ethernet driver">::log(
"Received frames: {}",