21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/machine/Network.h"
24#include "pedigree/kernel/network/IpAddress.h"
25#include "pedigree/kernel/network/MacAddress.h"
26#include "pedigree/kernel/process/TerminationDeferral.h"
27#include "pedigree/kernel/process/Thread.h"
28#include "pedigree/kernel/processor/Processor.h"
29#include "pedigree/kernel/processor/ProcessorInformation.h"
30#include "pedigree/kernel/time/Time.h"
31#include "pedigree/kernel/utilities/MemoryPool.h"
32#include "pedigree/kernel/utilities/PointerGuard.h"
33#include "pedigree/kernel/utilities/Vector.h"
34#include "pedigree/kernel/utilities/utility.h"
36#include "modules/system/network-stack/NetworkStack.h"
37#include "modules/system/usb/UsbConstants.h"
40constexpr size_t MaxPacketBytes = 1518;
41constexpr size_t RxUsbOverhead = 8;
42constexpr uint32_t ControlTransferTimeoutMs = 250;
43constexpr uint32_t BulkTransferTimeoutMs = 1000;
44constexpr Time::Timestamp ResetTimeout = 20 * Time::Multiplier::Millisecond;
45constexpr Time::Timestamp SharedOperationTimeout = 20 * Time::Multiplier::Millisecond;
46constexpr Time::Timestamp LinkWaitTimeout = Time::Multiplier::Second;
47constexpr Time::Timestamp LinkPollInterval = 50 * Time::Multiplier::Millisecond;
48constexpr Time::Timestamp TxReadyTimeout = 100 * Time::Multiplier::Millisecond;
49constexpr Time::Timestamp RegisterPollInterval = Time::Multiplier::Millisecond;
50constexpr Time::Timestamp SharedPollInterval = Time::Multiplier::Millisecond;
51constexpr size_t ResetPollLimit = 16;
52constexpr size_t SharedPollLimit = 16;
53constexpr size_t LinkPollLimit = 16;
54constexpr size_t TxReadyPollLimit = 16;
55constexpr size_t TxPaddingLimit = 3;
57constexpr uint8_t NetworkStatusLinkUp = 1 << 6;
58constexpr uint8_t NetworkStatusTxBusy = 1 << 4;
59constexpr uint8_t PhyControlBusy = 1;
60constexpr uint8_t RxStatusErrorMask = 0xBF;
69 m_SharedRegisterLock(),
70 m_IncomingPackets(false),
71 m_RxQueueHead(nullptr),
72 m_RxQueueTail(nullptr),
73 m_RxPacketQueueLock(),
94 m_ReceiveWorker.stop();
96 m_PacketWorker.stop();
99 Packet* packets =
nullptr;
102 packets = m_RxQueueHead;
103 m_RxQueueHead =
nullptr;
104 m_RxQueueTail =
nullptr;
107 Packet* packet = packets;
108 packets = packet->next;
109 if (packet->buffer) {
118 for (
size_t i = 0; i <
m_pInterface->endpointList.count(); i++) {
120 if (!
m_pInEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bIn)
122 if (!
m_pOutEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bOut)
129 ERROR(
"dm9601: no bulk IN endpoint");
134 ERROR(
"dm9601: no bulk OUT endpoint");
138 uint8_t mac[6]
ALIGN(16) = {};
139 for (
size_t i = 0; i < 3; ++i) {
142 ERROR(
"dm9601: could not read its MAC address from EEPROM");
145 mac[i * 2] =
static_cast<uint8_t
>(word);
146 mac[i * 2 + 1] =
static_cast<uint8_t
>(word >> 8);
147 m_StationInfo.mac.setMac(mac[i * 2], i * 2);
148 m_StationInfo.mac.setMac(mac[i * 2 + 1], i * 2 + 1);
151 NOTICE(
"DM9601: MAC " << m_StationInfo.mac[0] <<
":" << m_StationInfo.mac[1] <<
":"
152 << m_StationInfo.mac[2] <<
":" << m_StationInfo.mac[3] <<
":"
153 << m_StationInfo.mac[4] <<
":" << m_StationInfo.mac[5]);
155 if (!resetDevice()) {
156 ERROR(
"dm9601: device reset did not complete");
165 !
writeRegister(PhysicalAddress,
reinterpret_cast<uintptr_t
>(mac),
sizeof(mac)) ||
167 ERROR(
"dm9601: device setup transfer failed");
171 if (!waitForLink()) {
172 ERROR(
"dm9601: could not read initial link status");
179 pThread->setName(
"DM9601 RX worker");
180 m_PacketWorker.adopt(pThread);
183 pThread->setName(
"DM9601 RX loop");
184 m_ReceiveWorker.adopt(pThread);
192int Dm9601::recvTrampoline(
void* p) {
194 pDm9601->receiveLoop();
198int Dm9601::trampoline(
void* p) {
200 pDm9601->receiveThread();
204void Dm9601::receiveThread() {
214 Packet* pPacket =
nullptr;
217 pPacket = m_RxQueueHead;
219 m_RxQueueHead = pPacket->next;
221 m_RxQueueTail =
nullptr;
234 uintptr_t buffer = pPacket->buffer;
243void Dm9601::receiveLoop() {
252 if (!m_Operations.
tryAcquire(operation) || !m_Running || !buffer || !nBytes ||
257 size_t payloadBytes = nBytes < 64 ? 64 : nBytes;
258 size_t txSize = payloadBytes + 2;
259 for (
size_t padding = 0;
260 padding < TxPaddingLimit && ((txSize & 1) || !(txSize %
m_pOutEndpoint->nMaxPacketSize));
268 const size_t txWords = (txSize +
sizeof(uint16_t) - 1) /
sizeof(uint16_t);
269 uint16_t* pBuffer =
new uint16_t[txWords];
271 ByteSet(pBuffer, 0, txWords *
sizeof(uint16_t));
272 *pBuffer = HOST_TO_LITTLE16(
static_cast<uint16_t
>(payloadBytes));
273 MemoryCopy(&pBuffer[1],
reinterpret_cast<void*
>(buffer), nBytes);
277 if (!m_Running || !waitForTxReady())
281 syncOut(
m_pOutEndpoint,
reinterpret_cast<uintptr_t
>(pBuffer), txSize, BulkTransferTimeoutMs);
282 if (ret !=
static_cast<ssize_t
>(txSize)) {
283 WARNING(
"dm9601: transmit transfer failed or was short (" << ret <<
"/" << txSize <<
")");
288 uint8_t txStatus
ALIGN(16) = 0;
289 uint8_t networkStatus
ALIGN(16) = 0;
290 const uint8_t txStatusRegister =
static_cast<uint8_t
>(TxStatus1 +
m_TxPacket);
292 if (!
readRegister(txStatusRegister,
reinterpret_cast<uintptr_t
>(&txStatus), 1)) {
293 WARNING(
"dm9601: could not read transmit status");
299 if (!
readRegister(NetworkStatus,
reinterpret_cast<uintptr_t
>(&networkStatus), 1)) {
300 WARNING(
"dm9601: could not clear network status after transmit");
307void Dm9601::doReceive() {
314 syncIn(
m_pInEndpoint, buff, MaxPacketBytes + RxUsbOverhead, BulkTransferTimeoutMs);
318 DEBUG_LOG(
"dm9601: receive transfer did not complete: " << ret);
330 WARNING(
"dm9601: receive transfer was too short: " << ret);
336 uint8_t* pBuffer =
reinterpret_cast<uint8_t*
>(buff);
337 uint8_t rxstatus = pBuffer[0];
338 const uint16_t wireLength =
339 static_cast<uint16_t
>(pBuffer[1]) |
static_cast<uint16_t
>(pBuffer[2] << 8);
340 if (wireLength < 4 || wireLength >
static_cast<size_t>(ret - 3)) {
341 WARNING(
"dm9601: invalid receive length " << wireLength <<
" in " << ret <<
" byte transfer");
346 const size_t len = wireLength - 4;
348 if ((rxstatus & RxStatusErrorMask) || !len || len > MaxPacketBytes) {
349 WARNING(
"dm9601: rx failure: " << rxstatus <<
", length was " << len);
355 Packet* pPacket =
new Packet;
356 pPacket->buffer = buff;
359 pPacket->next =
nullptr;
366 m_RxQueueTail->next = pPacket;
368 m_RxQueueHead = pPacket;
369 m_RxQueueTail = pPacket;
384 if (m_StationInfo.dnsServers)
385 delete[] m_StationInfo.dnsServers;
388 m_StationInfo.ipv4 = info.ipv4;
389 NOTICE(
"DM9601: Setting ipv4, " << info.ipv4.toString() <<
", " << m_StationInfo.ipv4.toString()
391 m_StationInfo.ipv6 = info.ipv6;
393 m_StationInfo.subnetMask = info.subnetMask;
394 NOTICE(
"DM9601: Setting subnet mask, " << info.subnetMask.toString() <<
", "
395 << m_StationInfo.subnetMask.toString() <<
"...");
396 m_StationInfo.
gateway = info.gateway;
397 NOTICE(
"DM9601: Setting gateway, " << info.gateway.toString() <<
", "
398 << m_StationInfo.
gateway.toString() <<
"...");
401 m_StationInfo.dnsServers = info.dnsServers;
403 NOTICE(
"DM9601: Setting DNS servers [" <<
Dec << m_StationInfo.
nDnsServers <<
Hex
404 <<
" servers being set]...");
410 return m_StationInfo;
414 if (!buffer || (nBytes > 0xFF))
416 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
417 static_cast<uint8_t
>(UsbRequestDirection::In)),
418 ReadRegister, 0, reg, nBytes, buffer, ControlTransferTimeoutMs);
422 if (!buffer || (nBytes > 0xFF))
424 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
425 static_cast<uint8_t
>(UsbRequestDirection::Out)),
426 WriteRegister, 0, reg, nBytes, buffer, ControlTransferTimeoutMs);
430 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
431 static_cast<uint8_t
>(UsbRequestDirection::Out)),
432 WriteRegister1, data, reg, 0, 0, ControlTransferTimeoutMs);
436 if (!buffer || (nBytes > 0xFF))
438 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
439 static_cast<uint8_t
>(UsbRequestDirection::In)),
440 ReadMemory, 0, offset, nBytes, buffer, ControlTransferTimeoutMs);
444 if (!buffer || (nBytes > 0xFF))
446 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
447 static_cast<uint8_t
>(UsbRequestDirection::Out)),
448 WriteMemory, 0, offset, nBytes, buffer, ControlTransferTimeoutMs);
452 return controlRequest(
static_cast<uint8_t
>(
static_cast<uint8_t
>(UsbRequestType::Vendor) |
453 static_cast<uint8_t
>(UsbRequestDirection::Out)),
454 WriteMemory1, data, offset, 0, 0, ControlTransferTimeoutMs);
458 return readSharedWord(
false, offset, value);
462 return writeSharedWord(
false, offset, data);
466 return readSharedWord(
true, offset, value);
470 return writeSharedWord(
true, offset, data);
473bool Dm9601::readSharedWord(
bool phy, uint8_t offset, uint16_t& value) {
475 uint16_t rawValue
ALIGN(16) = 0;
476 const uint8_t address = phy ?
static_cast<uint8_t
>(offset | 0x40) : offset;
477 const uint8_t command = phy ? 0x0C : 0x04;
480 !waitForSharedOperation()) {
486 !
readRegister(PhyLowByte,
reinterpret_cast<uintptr_t
>(&rawValue),
sizeof(rawValue))) {
490 value = LITTLE_TO_HOST16(rawValue);
494bool Dm9601::writeSharedWord(
bool phy, uint8_t offset, uint16_t value) {
496 uint16_t rawValue
ALIGN(16) = HOST_TO_LITTLE16(value);
497 const uint8_t address = phy ?
static_cast<uint8_t
>(offset | 0x40) : offset;
498 const uint8_t command = phy ? 0x1A : 0x12;
500 if (!
writeRegister(PhyLowByte,
reinterpret_cast<uintptr_t
>(&rawValue),
sizeof(rawValue)) ||
502 !waitForSharedOperation()) {
510bool Dm9601::waitForSharedOperation() {
511 const Time::Timestamp deadline = Time::getTicks() + SharedOperationTimeout;
512 for (
size_t poll = 0; poll < SharedPollLimit; ++poll) {
513 uint8_t control
ALIGN(16) = 0;
514 if (!
readRegister(PhyControl,
reinterpret_cast<uintptr_t
>(&control),
sizeof(control))) {
517 if (!(control & PhyControlBusy))
519 if (Time::getTicks() >= deadline || poll + 1 == SharedPollLimit ||
520 !Time::delay(SharedPollInterval))
524 WARNING(
"dm9601: EEPROM/PHY operation timed out");
528bool Dm9601::resetDevice() {
529 if (!
writeRegister(NetworkControl, 1) || !Time::delay(20 * Time::Multiplier::Microsecond)) {
533 const Time::Timestamp deadline = Time::getTicks() + ResetTimeout;
534 for (
size_t poll = 0; poll < ResetPollLimit; ++poll) {
535 uint8_t control
ALIGN(16) = 0;
536 if (!
readRegister(NetworkControl,
reinterpret_cast<uintptr_t
>(&control),
sizeof(control))) {
541 if (Time::getTicks() >= deadline || poll + 1 == ResetPollLimit ||
542 !Time::delay(RegisterPollInterval))
549bool Dm9601::waitForLink() {
550 const Time::Timestamp deadline = Time::getTicks() + LinkWaitTimeout;
551 for (
size_t poll = 0; poll < LinkPollLimit; ++poll) {
552 uint8_t status
ALIGN(16) = 0;
553 if (!
readRegister(NetworkStatus,
reinterpret_cast<uintptr_t
>(&status),
sizeof(status))) {
556 if (status & NetworkStatusLinkUp)
558 if (Time::getTicks() >= deadline || poll + 1 == LinkPollLimit)
560 if (!Time::delay(LinkPollInterval))
564 NOTICE(
"dm9601: link is down; continuing without blocking USB discovery");
568bool Dm9601::waitForTxReady() {
569 const Time::Timestamp deadline = Time::getTicks() + TxReadyTimeout;
570 for (
size_t poll = 0; poll < TxReadyPollLimit; ++poll) {
574 uint8_t status
ALIGN(16) = 0;
575 if (!
readRegister(NetworkStatus,
reinterpret_cast<uintptr_t
>(&status),
sizeof(status))) {
578 if (!(status & NetworkStatusTxBusy))
580 if (Time::getTicks() >= deadline || poll + 1 == TxReadyPollLimit ||
581 !Time::delay(RegisterPollInterval))
585 WARNING(
"dm9601: transmitter remained busy");
Device * getParent() const
bool writeMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Writes data from a buffer into device memory.
bool writeRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Writes data from a buffer to a register.
bool writeMii(uint8_t offset, uint16_t data)
Writes a 16-bit value to the external MII.
Mutex m_SharedRegisterLock
Endpoint * m_pOutEndpoint
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
virtual bool send(size_t nBytes, uintptr_t buffer)
bool writeEeprom(uint8_t offset, uint16_t data)
Writes a 16-bit value to the device EEPROM.
bool readRegister(uint8_t reg, uintptr_t buffer, size_t nBytes)
Reads data from a register into a buffer.
bool readMemory(uint16_t offset, uintptr_t buffer, size_t nBytes)
Reads data from device memory into a buffer.
bool readMii(uint8_t offset, uint16_t &value)
Reads a 16-bit value from the external MII.
Semaphore m_IncomingPackets
virtual bool setStationInfo(const StationInfo &info)
virtual const StationInfo & getStationInfo()
bool readEeprom(uint8_t offset, uint16_t &value)
Reads a 16-bit value from the device EEPROM.
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
MemoryPool & getMemPool()
void deRegisterDevice(Network *pDevice)
static NetworkStack & instance()
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
void registerDevice(Network *pDevice)
MUST_USE_RESULT bool tryAcquire(Lease &lease)
static ProcessorInformation & information()
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
size_t nDnsServers
Can contain IPv6 addresses.
IpAddress gateway
Automatically calculated?
@ Continue
No unwind necessary, carry on as normal.
Interface * m_pInterface
Interface in use.
bool controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Performs an USB control request.
UsbState m_UsbState
The current state of the device.