Kernel: Fix RTL8169 driver
This now works properly on real hardware. Main issue was a race condition with now ISR was handled in the interrupt handler. We now loop until we read back ISR as zero
This commit is contained in:
@@ -7,25 +7,25 @@ namespace Kernel
|
|||||||
|
|
||||||
enum RTL8169_IO_REGS : uint16_t
|
enum RTL8169_IO_REGS : uint16_t
|
||||||
{
|
{
|
||||||
RTL8169_IO_IDR0 = 0x00,
|
RTL8169_IO_IDR0 = 0x00,
|
||||||
RTL8169_IO_IDR1 = 0x01,
|
RTL8169_IO_IDR1 = 0x01,
|
||||||
RTL8169_IO_IDR2 = 0x02,
|
RTL8169_IO_IDR2 = 0x02,
|
||||||
RTL8169_IO_IDR3 = 0x03,
|
RTL8169_IO_IDR3 = 0x03,
|
||||||
RTL8169_IO_IDR4 = 0x04,
|
RTL8169_IO_IDR4 = 0x04,
|
||||||
RTL8169_IO_IDR5 = 0x05,
|
RTL8169_IO_IDR5 = 0x05,
|
||||||
|
|
||||||
RTL8169_IO_TNPDS = 0x20,
|
RTL8169_IO_TNPDS = 0x20,
|
||||||
RTL8169_IO_CR = 0x37,
|
RTL8169_IO_CR = 0x37,
|
||||||
RTL8169_IO_TPPoll = 0x38,
|
RTL8169_IO_TPPoll = 0x38,
|
||||||
RTL8169_IO_IMR = 0x3C,
|
RTL8169_IO_IMR = 0x3C,
|
||||||
RTL8169_IO_ISR = 0x3E,
|
RTL8169_IO_ISR = 0x3E,
|
||||||
RTL8169_IO_TCR = 0x40,
|
RTL8169_IO_TCR = 0x40,
|
||||||
RTL8169_IO_RCR = 0x44,
|
RTL8169_IO_RCR = 0x44,
|
||||||
RTL8169_IO_9346CR = 0x50,
|
RTL8169_IO_PHYSts = 0x6C,
|
||||||
RTL8169_IO_PHYSts = 0x6C,
|
RTL8169_IO_RMS = 0xDA,
|
||||||
RTL8169_IO_RMS = 0xDA,
|
RTL8169_IO_CPlusCR = 0xE0,
|
||||||
RTL8169_IO_RDSAR = 0xE4,
|
RTL8169_IO_RDSAR = 0xE4,
|
||||||
RTL8169_IO_MTPS = 0xEC,
|
RTL8169_IO_MTPS = 0xEC,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RTL8169_CR : uint8_t
|
enum RTL8169_CR : uint8_t
|
||||||
|
|||||||
@@ -64,14 +64,17 @@ namespace Kernel
|
|||||||
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
BAN::UniqPtr<DMARegion> m_rx_descriptor_region;
|
||||||
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
|
||||||
|
|
||||||
SpinLock m_lock;
|
BAN::Atomic<bool> m_rx_thread_should_die { false };
|
||||||
|
BAN::Atomic<bool> m_rx_thread_is_dead { true };
|
||||||
|
|
||||||
bool m_thread_should_die { false };
|
uint32_t m_rx_head { 0 };
|
||||||
BAN::Atomic<bool> m_thread_is_dead { true };
|
SpinLock m_rx_lock;
|
||||||
ThreadBlocker m_thread_blocker;
|
ThreadBlocker m_rx_blocker;
|
||||||
|
|
||||||
uint32_t m_rx_current { 0 };
|
BAN::Atomic<uint32_t> m_tx_head { 0 };
|
||||||
size_t m_tx_current { 0 };
|
BAN::Atomic<uint32_t> m_tx_commit { 0 };
|
||||||
|
SpinLock m_tx_lock;
|
||||||
|
ThreadBlocker m_tx_blocker;
|
||||||
|
|
||||||
BAN::MACAddress m_mac_address {};
|
BAN::MACAddress m_mac_address {};
|
||||||
BAN::Atomic<bool> m_link_up { false };
|
BAN::Atomic<bool> m_link_up { false };
|
||||||
|
|||||||
@@ -47,30 +47,29 @@ namespace Kernel
|
|||||||
|
|
||||||
TRY(reset());
|
TRY(reset());
|
||||||
|
|
||||||
|
// disable rx, tx, checksum offload
|
||||||
|
m_io_bar_region->write16(RTL8169_IO_CPlusCR, 0x0000);
|
||||||
|
m_io_bar_region->write8 (RTL8169_IO_CR, 0x00);
|
||||||
|
|
||||||
dprintln(" reset done");
|
dprintln(" reset done");
|
||||||
|
|
||||||
for (size_t i = 0; i < 6; i++)
|
for (size_t i = 0; i < 6; i++)
|
||||||
m_mac_address.address[i] = m_io_bar_region->read8(RTL8169_IO_IDR0 + i);
|
m_mac_address.address[i] = m_io_bar_region->read8(RTL8169_IO_IDR0 + i);
|
||||||
dprintln(" MAC {}", m_mac_address);
|
dprintln(" MAC {}", m_mac_address);
|
||||||
|
|
||||||
// unlock config registers
|
|
||||||
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_CONFIG);
|
|
||||||
|
|
||||||
TRY(initialize_rx());
|
TRY(initialize_rx());
|
||||||
TRY(initialize_tx());
|
TRY(initialize_tx());
|
||||||
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RE | RTL8169_CR_TE);
|
m_io_bar_region->write8(RTL8169_IO_CR, RTL8169_CR_RE | RTL8169_CR_TE);
|
||||||
dprintln(" descriptors initialized");
|
dprintln(" descriptors initialized");
|
||||||
|
|
||||||
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||||
if (m_link_up)
|
dprintln(" link status {}", link_up() ? "UP" : "DOWN");
|
||||||
|
if (link_up())
|
||||||
dprintln(" link speed {}", link_speed());
|
dprintln(" link speed {}", link_speed());
|
||||||
|
|
||||||
TRY(enable_interrupt());
|
TRY(enable_interrupt());
|
||||||
dprintln(" interrupts enabled");
|
dprintln(" interrupts enabled");
|
||||||
|
|
||||||
// lock config registers
|
|
||||||
m_io_bar_region->write8(RTL8169_IO_9346CR, RTL8169_9346CR_MODE_NORMAL);
|
|
||||||
|
|
||||||
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
|
auto* thread = TRY(Thread::create_kernel([](void* rtl8169_ptr) {
|
||||||
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
|
static_cast<RTL8169*>(rtl8169_ptr)->receive_thread();
|
||||||
}, this));
|
}, this));
|
||||||
@@ -79,17 +78,17 @@ namespace Kernel
|
|||||||
delete thread;
|
delete thread;
|
||||||
return ret.release_error();
|
return ret.release_error();
|
||||||
}
|
}
|
||||||
m_thread_is_dead = false;
|
m_rx_thread_is_dead = false;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
RTL8169::~RTL8169()
|
RTL8169::~RTL8169()
|
||||||
{
|
{
|
||||||
m_thread_should_die = true;
|
m_rx_thread_should_die = true;
|
||||||
m_thread_blocker.unblock();
|
m_rx_blocker.unblock();
|
||||||
|
|
||||||
while (!m_thread_is_dead)
|
while (!m_rx_thread_is_dead)
|
||||||
Processor::yield();
|
Processor::yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,32 +109,26 @@ namespace Kernel
|
|||||||
m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
m_rx_buffer_region = TRY(DMARegion::create(m_rx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
||||||
m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor)));
|
m_rx_descriptor_region = TRY(DMARegion::create(m_rx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||||
|
|
||||||
|
auto* rx_descriptors = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr());
|
||||||
for (size_t i = 0; i < m_rx_descriptor_count; i++)
|
for (size_t i = 0; i < m_rx_descriptor_count; i++)
|
||||||
{
|
{
|
||||||
const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * s_buffer_size;
|
const paddr_t rx_buffer_paddr = m_rx_buffer_region->paddr() + i * s_buffer_size;
|
||||||
|
rx_descriptors[i].command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||||
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
rx_descriptors[i].vlan = 0;
|
||||||
if (i == m_rx_descriptor_count - 1)
|
rx_descriptors[i].buffer_low = rx_buffer_paddr & 0xFFFFFFFF;
|
||||||
command |= RTL8169_DESC_CMD_EOR;
|
rx_descriptors[i].buffer_high = rx_buffer_paddr >> 32;
|
||||||
|
|
||||||
auto& rx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[i];
|
|
||||||
rx_descriptor.command = command;
|
|
||||||
rx_descriptor.vlan = 0;
|
|
||||||
rx_descriptor.buffer_low = rx_buffer_paddr & 0xFFFFFFFF;
|
|
||||||
rx_descriptor.buffer_high = rx_buffer_paddr >> 32;
|
|
||||||
}
|
}
|
||||||
|
rx_descriptors[m_rx_descriptor_count - 1].command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
|
||||||
// configure rx descriptor addresses
|
// configure rx descriptor addresses
|
||||||
m_io_bar_region->write32(RTL8169_IO_RDSAR + 0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
|
||||||
m_io_bar_region->write32(RTL8169_IO_RDSAR + 4, m_rx_descriptor_region->paddr() >> 32);
|
m_io_bar_region->write32(RTL8169_IO_RDSAR + 4, m_rx_descriptor_region->paddr() >> 32);
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_RDSAR + 0, m_rx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||||
|
|
||||||
// configure receibe control (no fifo threshold, max dma burst 1024, accept physical match, broadcast, multicast)
|
// configure receive control (no fifo threshold, max dma burst unlimited, broadcast, multicast, accept physical match)
|
||||||
m_io_bar_region->write32(RTL8169_IO_RCR,
|
m_io_bar_region->write32(RTL8169_IO_RCR,
|
||||||
RTL8169_RCR_RXFTH_NO | RTL8169_RCR_MXDMA_1024 | RTL8169_RCR_AB | RTL8169_RCR_AM | RTL8169_RCR_APM
|
RTL8169_RCR_RXFTH_NO | RTL8169_RCR_MXDMA_UNLIMITED | RTL8169_RCR_AB | RTL8169_RCR_AM | RTL8169_RCR_APM
|
||||||
);
|
);
|
||||||
|
|
||||||
m_io_bar_region->write32(0x44, 0b111111 | (0b111 << 8) | (0b111 << 13));
|
|
||||||
|
|
||||||
// configure max rx packet size
|
// configure max rx packet size
|
||||||
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
|
m_io_bar_region->write16(RTL8169_IO_RMS, RTL8169_RMS_MAX);
|
||||||
|
|
||||||
@@ -147,27 +140,23 @@ namespace Kernel
|
|||||||
m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
m_tx_buffer_region = TRY(DMARegion::create(m_tx_descriptor_count * s_buffer_size, PageTable::MemoryType::Normal));
|
||||||
m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor)));
|
m_tx_descriptor_region = TRY(DMARegion::create(m_tx_descriptor_count * sizeof(RTL8169Descriptor)));
|
||||||
|
|
||||||
|
auto* tx_descriptors = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr());
|
||||||
for (size_t i = 0; i < m_tx_descriptor_count; i++)
|
for (size_t i = 0; i < m_tx_descriptor_count; i++)
|
||||||
{
|
{
|
||||||
const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * s_buffer_size;
|
const paddr_t tx_buffer_paddr = m_tx_buffer_region->paddr() + i * s_buffer_size;
|
||||||
|
tx_descriptors[i].command = 0;
|
||||||
uint32_t command = 0;
|
tx_descriptors[i].vlan = 0;
|
||||||
if (i == m_tx_descriptor_count - 1)
|
tx_descriptors[i].buffer_low = tx_buffer_paddr & 0xFFFFFFFF;
|
||||||
command |= RTL8169_DESC_CMD_EOR;
|
tx_descriptors[i].buffer_high = tx_buffer_paddr >> 32;
|
||||||
|
|
||||||
auto& tx_descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[i];
|
|
||||||
tx_descriptor.command = command;
|
|
||||||
tx_descriptor.vlan = 0;
|
|
||||||
tx_descriptor.buffer_low = tx_buffer_paddr & 0xFFFFFFFF;
|
|
||||||
tx_descriptor.buffer_high = tx_buffer_paddr >> 32;
|
|
||||||
}
|
}
|
||||||
|
tx_descriptors[m_tx_descriptor_count - 1].command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
|
||||||
// configure tx descriptor addresses
|
// configure tx descriptor addresses
|
||||||
m_io_bar_region->write32(RTL8169_IO_TNPDS + 0, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
|
||||||
m_io_bar_region->write32(RTL8169_IO_TNPDS + 4, m_tx_descriptor_region->paddr() >> 32);
|
m_io_bar_region->write32(RTL8169_IO_TNPDS + 4, m_tx_descriptor_region->paddr() >> 32);
|
||||||
|
m_io_bar_region->write32(RTL8169_IO_TNPDS + 0, m_tx_descriptor_region->paddr() & 0xFFFFFFFF);
|
||||||
|
|
||||||
// configure transmit control (standard ifg, max dma burst 1024)
|
// configure transmit control (standard ifg, max dma burst unlimited)
|
||||||
m_io_bar_region->write32(RTL8169_IO_TCR, RTL8169_TCR_IFG_0 | RTL8169_TCR_MXDMA_1024);
|
m_io_bar_region->write32(RTL8169_IO_TCR, RTL8169_TCR_IFG_0 | RTL8169_TCR_MXDMA_UNLIMITED);
|
||||||
|
|
||||||
// configure max tx packet size
|
// configure max tx packet size
|
||||||
m_io_bar_region->write8(RTL8169_IO_MTPS, RTL8169_MTPS_MAX);
|
m_io_bar_region->write8(RTL8169_IO_MTPS, RTL8169_MTPS_MAX);
|
||||||
@@ -181,14 +170,13 @@ namespace Kernel
|
|||||||
m_pci_device.enable_interrupt(0, *this);
|
m_pci_device.enable_interrupt(0, *this);
|
||||||
|
|
||||||
m_io_bar_region->write16(RTL8169_IO_IMR,
|
m_io_bar_region->write16(RTL8169_IO_IMR,
|
||||||
RTL8169_IR_ROK
|
RTL8169_IR_ROK |
|
||||||
| RTL8169_IR_RER
|
RTL8169_IR_RER |
|
||||||
| RTL8169_IR_TOK
|
RTL8169_IR_TOK |
|
||||||
| RTL8169_IR_TER
|
RTL8169_IR_TER |
|
||||||
| RTL8169_IR_RDU
|
RTL8169_IR_RDU |
|
||||||
| RTL8169_IR_LinkChg
|
RTL8169_IR_LinkChg |
|
||||||
| RTL8169_IR_FVOW
|
RTL8169_IR_FVOW
|
||||||
| RTL8169_IR_TDU
|
|
||||||
);
|
);
|
||||||
m_io_bar_region->write16(RTL8169_IO_ISR, 0xFFFF);
|
m_io_bar_region->write16(RTL8169_IO_ISR, 0xFFFF);
|
||||||
|
|
||||||
@@ -214,20 +202,23 @@ namespace Kernel
|
|||||||
if (!link_up())
|
if (!link_up())
|
||||||
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
return BAN::Error::from_errno(EADDRNOTAVAIL);
|
||||||
|
|
||||||
auto state = m_lock.lock();
|
const auto interrupt_state = Processor::get_interrupt_state();
|
||||||
|
Processor::set_interrupt_state(InterruptState::Disabled);
|
||||||
|
|
||||||
const uint32_t tx_current = m_tx_current;
|
const uint32_t tx_current_nowrap = m_tx_head.fetch_add(1);
|
||||||
m_tx_current = (m_tx_current + 1) % m_tx_descriptor_count;
|
const uint32_t tx_current = tx_current_nowrap % m_tx_descriptor_count;
|
||||||
|
|
||||||
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current];
|
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_tx_descriptor_region->vaddr())[tx_current];
|
||||||
while (descriptor.command & RTL8169_DESC_CMD_OWN)
|
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||||
{
|
{
|
||||||
SpinLockAsMutex smutex(m_lock, state);
|
SpinLockGuard guard(m_tx_lock);
|
||||||
m_thread_blocker.block_indefinite(&smutex);
|
while (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||||
|
{
|
||||||
|
SpinLockGuardAsMutex smutex(guard);
|
||||||
|
m_tx_blocker.block_indefinite(&smutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_lock.unlock(state);
|
|
||||||
|
|
||||||
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * s_buffer_size);
|
auto* tx_buffer = reinterpret_cast<uint8_t*>(m_tx_buffer_region->vaddr() + tx_current * s_buffer_size);
|
||||||
|
|
||||||
// write packet
|
// write packet
|
||||||
@@ -245,25 +236,31 @@ namespace Kernel
|
|||||||
|
|
||||||
// give packet ownership to NIC
|
// give packet ownership to NIC
|
||||||
uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS;
|
uint32_t command = packet_size | RTL8169_DESC_CMD_OWN | RTL8169_DESC_CMD_LS | RTL8169_DESC_CMD_FS;
|
||||||
if (tx_current >= m_tx_descriptor_count - 1)
|
if (tx_current == m_tx_descriptor_count - 1)
|
||||||
command |= RTL8169_DESC_CMD_EOR;
|
command |= RTL8169_DESC_CMD_EOR;
|
||||||
descriptor.command = command;
|
descriptor.command = command;
|
||||||
|
|
||||||
// notify NIC about new packet
|
// ring tx queue doorbell
|
||||||
m_io_bar_region->write8(RTL8169_IO_TPPoll, RTL8169_TPPoll_NPQ);
|
if (tx_current_nowrap == m_tx_commit.load())
|
||||||
|
m_io_bar_region->write8(RTL8169_IO_TPPoll, RTL8169_TPPoll_NPQ);
|
||||||
|
while (tx_current_nowrap != m_tx_commit.load())
|
||||||
|
Processor::pause();
|
||||||
|
m_tx_commit.add_fetch(1);
|
||||||
|
|
||||||
|
Processor::set_interrupt_state(interrupt_state);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTL8169::receive_thread()
|
void RTL8169::receive_thread()
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
SpinLockGuard rx_lock_guard(m_rx_lock);
|
||||||
|
|
||||||
while (!m_thread_should_die)
|
while (!m_rx_thread_should_die)
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_current];
|
auto& descriptor = reinterpret_cast<volatile RTL8169Descriptor*>(m_rx_descriptor_region->vaddr())[m_rx_head];
|
||||||
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
if (descriptor.command & RTL8169_DESC_CMD_OWN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -277,54 +274,67 @@ namespace Kernel
|
|||||||
; // descriptor has an error
|
; // descriptor has an error
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_lock.unlock(InterruptState::Enabled);
|
m_rx_lock.unlock(InterruptState::Enabled);
|
||||||
|
|
||||||
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
NetworkManager::get().on_receive(*this, BAN::ConstByteSpan {
|
||||||
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_current * s_buffer_size),
|
reinterpret_cast<const uint8_t*>(m_rx_buffer_region->vaddr() + m_rx_head * s_buffer_size),
|
||||||
packet_length
|
packet_length
|
||||||
});
|
});
|
||||||
|
|
||||||
m_lock.lock();
|
m_rx_lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rx_current = (m_rx_current + 1) % m_rx_descriptor_count;
|
uint32_t command = 0x1FF8 | RTL8169_DESC_CMD_OWN;
|
||||||
|
if (m_rx_head == m_rx_descriptor_count - 1)
|
||||||
|
command |= RTL8169_DESC_CMD_EOR;
|
||||||
|
descriptor.command = command;
|
||||||
|
|
||||||
descriptor.command = descriptor.command | RTL8169_DESC_CMD_OWN;
|
m_rx_head = (m_rx_head + 1) % m_rx_descriptor_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpinLockAsMutex smutex(m_lock, InterruptState::Enabled);
|
SpinLockGuardAsMutex smutex(rx_lock_guard);
|
||||||
m_thread_blocker.block_indefinite(&smutex);
|
m_rx_blocker.block_indefinite(&smutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_thread_is_dead = true;
|
m_rx_thread_is_dead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RTL8169::handle_irq()
|
void RTL8169::handle_irq()
|
||||||
{
|
{
|
||||||
const uint16_t interrupt_status = m_io_bar_region->read16(RTL8169_IO_ISR);
|
uint16_t isr;
|
||||||
m_io_bar_region->write16(RTL8169_IO_ISR, interrupt_status);
|
while ((isr = m_io_bar_region->read16(RTL8169_IO_ISR)))
|
||||||
|
|
||||||
if (interrupt_status & RTL8169_IR_LinkChg)
|
|
||||||
{
|
{
|
||||||
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
m_io_bar_region->write16(RTL8169_IO_ISR, isr);
|
||||||
dprintln("link status -> {}", m_link_up.load());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interrupt_status & (RTL8169_IR_TOK | RTL8169_IR_ROK))
|
if (isr & RTL8169_IR_LinkChg)
|
||||||
{
|
{
|
||||||
SpinLockGuard _(m_lock);
|
m_link_up = m_io_bar_region->read8(RTL8169_IO_PHYSts) & RTL8169_PHYSts_LinkSts;
|
||||||
m_thread_blocker.unblock();
|
dprintln("link status {}", link_up() ? "UP" : "DOWN");
|
||||||
}
|
if (link_up())
|
||||||
|
dprintln("link speed {}", link_speed());
|
||||||
|
}
|
||||||
|
|
||||||
if (interrupt_status & RTL8169_IR_RER)
|
if (isr & (RTL8169_IR_TER | RTL8169_IR_TOK))
|
||||||
dwarnln("Rx error");
|
{
|
||||||
if (interrupt_status & RTL8169_IR_TER)
|
SpinLockGuard _(m_tx_lock);
|
||||||
dwarnln("Tx error");
|
m_tx_blocker.unblock();
|
||||||
if (interrupt_status & RTL8169_IR_RDU)
|
}
|
||||||
dwarnln("Rx descriptor not available");
|
|
||||||
if (interrupt_status & RTL8169_IR_FVOW)
|
if (isr & (RTL8169_IR_RER | RTL8169_IR_ROK))
|
||||||
dwarnln("Rx FIFO overflow");
|
{
|
||||||
// dont log TDU is sent after each sent packet
|
SpinLockGuard _(m_rx_lock);
|
||||||
|
m_rx_blocker.unblock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isr & RTL8169_IR_RER)
|
||||||
|
dwarnln("Rx error");
|
||||||
|
if (isr & RTL8169_IR_TER)
|
||||||
|
dwarnln("Tx error");
|
||||||
|
if (isr & RTL8169_IR_RDU)
|
||||||
|
dwarnln("Rx descriptor not available");
|
||||||
|
if (isr & RTL8169_IR_FVOW)
|
||||||
|
dwarnln("Rx FIFO overflow");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user