Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion source/drivers/networking/ethernet/RTL/8139.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static uint8 *tx_buffers[RTL8139_TX_DESC_COUNT];
static uint8 tx_cur;
static uint16 rx_cur;
static bool rtl8139_ready;
static bool rtl8139_irq_driven = false;

void read_mac_address() {
for (int i = 0; i < 6; i++) {
Expand All @@ -63,6 +64,7 @@ void rtl8139_init(struct rtl8139 *nic) {
return;
}
rtl8139_ready = false;
rtl8139_irq_driven = false;
info("Initialization started!", __FILE__);

outb(nic->io_base + RTL8139_REG_CONFIG1, 0x00);
Expand Down Expand Up @@ -100,6 +102,8 @@ void rtl8139_init(struct rtl8139 *nic) {
RTL8139_RCR_APM | RTL8139_RCR_AM | RTL8139_RCR_AB |
RTL8139_RCR_WRAP | RTL8139_RCR_MXDMA_UNLIMITED | RTL8139_RCR_RBLEN_8K);
outl(nic->io_base + RTL8139_REG_TCR, 0x00000700);

// Enable interrupts for RX ready, TX OK, RX overflow, TX error, RX error
outw(nic->io_base + RTL8139_REG_IMR, RTL8139_ISR_ROK | RTL8139_ISR_TOK | RTL8139_ISR_RXOVW | RTL8139_ISR_TER | RTL8139_ISR_RER);
outw(nic->io_base + RTL8139_REG_ISR, 0xFFFF);

Expand Down Expand Up @@ -133,7 +137,7 @@ bool rtl8139_send_packet(const uint8 *data, uint16 length) {
return yes;
}

// Receives a packet
// Receives a packet (polling mode)
bool rtl8139_receive_packet(uint8 *buffer, uint16 *length) {
if (!rtl8139_ready || !RTL8139 || RTL8139->io_base == null || RTL8139->io_base == 0 || !rx_buffer || !buffer || !length) {
return no;
Expand All @@ -160,3 +164,67 @@ bool rtl8139_receive_packet(uint8 *buffer, uint16 *length) {
outw(RTL8139->io_base + RTL8139_REG_ISR, RTL8139_ISR_ROK | RTL8139_ISR_RER | RTL8139_ISR_RXOVW);
return yes;
}

/**
* @brief Process all available packets in the RX buffer and call the receive callback
* Used by both polling and interrupt-driven modes
*/
static void rtl8139_process_packets(void) {
uint8 buf[NET_FRAME_MAX];
uint16 len = 0;
while (rtl8139_receive_packet(buf, &len)) {
// rx_cb is set by the net_core module to ethernet_input
extern net_rx_callback_t rx_cb;
if (len >= 14 && len <= NET_FRAME_MAX) {
if (rx_cb)
rx_cb(buf, len);
}
len = 0;
}
}

/**
* @brief Interrupt handler for RTL8139 NIC
* Called when hardware raises IRQ with ROK (receive ok) or other status bits
* Processes packets directly in interrupt context for low latency
*/
void rtl8139_interrupt_handler(void) {
if (!rtl8139_ready || !RTL8139 || RTL8139->io_base == null)
return;

uint16_t status = inw(RTL8139->io_base + RTL8139_REG_ISR);

// Clear interrupt status bits immediately
outw(RTL8139->io_base + RTL8139_REG_ISR, status);

// Process RX packets if ROK (Receive OK) is set
if (status & RTL8139_ISR_ROK) {
rtl8139_process_packets();
}

// Handle TX completion
if (status & RTL8139_ISR_TOK) {
// Transmit successful - could log or update stats here if needed
}

// Handle errors
if (status & (RTL8139_ISR_RXOVW | RTL8139_ISR_TER | RTL8139_ISR_RER)) {
// RX overflow, TX error, or RX error occurred
// The driver continues - retransmit logic is in TCP layer
}
}

void rtl8139_irq_enable(void) {
if (!RTL8139 || RTL8139->io_base == null)
return;
rtl8139_irq_driven = true;
// IMR already set in rtl8139_init, just mark as active
}

void rtl8139_irq_disable(void) {
rtl8139_irq_driven = false;
}

bool rtl8139_is_irq_driven(void) {
return rtl8139_irq_driven;
}
28 changes: 25 additions & 3 deletions source/includes/drivers/rtl8139.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ extern struct rtl8139 *RTL8139;
void read_mac_address(void);

/**
* @brief Initialize RTL8139 NIC
* @brief Initialize RTL8139 NIC with interrupt support
*
* @param nic the pointer to RTL structure
*/
Expand All @@ -76,7 +76,7 @@ void rtl8139_init(struct rtl8139 *nic);
bool rtl8139_send_packet(const uint8 *data, uint16 length);

/**
* @brief Receives a packet
* @brief Receives a packet (polling mode - for manual retrieval if needed)
*
* @param buffer the received data
* @param length the length of buffer
Expand All @@ -85,4 +85,26 @@ bool rtl8139_send_packet(const uint8 *data, uint16 length);
*/
bool rtl8139_receive_packet(uint8 *buffer, uint16 *length);

#endif
/**
* @brief Interrupt handler for RTL8139 - processes incoming packets
* Called from ISR context when hardware raises interrupt
*/
void rtl8139_interrupt_handler(void);

/**
* @brief Enable interrupt-driven packet processing for RTL8139
* Allows packets to be processed when hardware IRQ fires instead of polling
*/
void rtl8139_irq_enable(void);

/**
* @brief Disable interrupt-driven packet processing
*/
void rtl8139_irq_disable(void);

/**
* @brief Check if interrupt-driven mode is active
*/
bool rtl8139_is_irq_driven(void);

#endif
21 changes: 12 additions & 9 deletions source/kernel/C/interrupts/isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,17 @@ void irqHandler(InterruptFrame *frame) {
handler(frame);
}

/**
* @brief RTL8139 interrupt handler - called when the NIC raises an interrupt
*
* This handler is registered for the RTL8139 IRQ line and processes:
* - ROK (Receive OK): incoming packets are processed and passed to the network stack
* - TOK (Transmit OK): transmit completion is acknowledged
* - Error conditions: overflow, transmit errors, receive errors
*
* Packets are processed in interrupt context for minimum latency.
*/
void rtl8139_handler(InterruptFrame *frame) {
(void)frame;
uint16_t status = inw(RTL8139->io_base + 0x3e);
outw(RTL8139->io_base + 0x3E, 0x05);
if (status & TOK) {
info("Successfully sent a packet!", __FILE__);
}
if (status & ROK) {
info("Successfully recieved a packet!", __FILE__);
}
(void)frame; // unused in this context
rtl8139_interrupt_handler();
}
13 changes: 13 additions & 0 deletions source/kernel/C/net/net_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ int net_packet_pull(net_packet_t *pkt, size_t len, void **hdr) {
void netif_init(void) {
netif_get_mac(net_cfg.mac);
netif_set_rx_callback(ethernet_input);
// Enable interrupt-driven mode for RTL8139 if available
rtl8139_irq_enable();
}

int netif_send(const void *frame, size_t len) {
Expand All @@ -133,9 +135,20 @@ int netif_send(const void *frame, size_t len) {
return rtl8139_send_packet((const uint8 *)frame, (uint16)len) ? NET_OK : NET_ERR;
}

/**
* @brief Poll for network packets
*
* If RTL8139 is in interrupt-driven mode, polling is largely a no-op since packets
* are processed in the IRQ handler. However, we keep this for:
* 1. Compatibility with existing code
* 2. Fallback if interrupts are temporarily disabled
* 3. Safety margin to catch any missed packets
*/
void netif_poll(void) {
uint8 buf[NET_FRAME_MAX];
uint16 len = 0;
// Keep polling loop for backward compatibility and as safety fallback
// In interrupt-driven mode, most packets are handled by rtl8139_interrupt_handler
while (rtl8139_receive_packet(buf, &len)) {
if (rx_cb && len >= 14 && len <= NET_FRAME_MAX)
rx_cb(buf, len);
Expand Down
Loading