mirror of
https://github.com/wichtounet/thor-os.git
synced 2025-09-18 17:15:09 -04:00
Implement packet transmission
This commit is contained in:
parent
ad6cd47457
commit
f12c035dc6
@ -12,6 +12,8 @@
|
|||||||
#include "virtual_allocator.hpp"
|
#include "virtual_allocator.hpp"
|
||||||
#include "interrupts.hpp"
|
#include "interrupts.hpp"
|
||||||
#include "paging.hpp"
|
#include "paging.hpp"
|
||||||
|
#include "semaphore.hpp"
|
||||||
|
#include "paging.hpp"
|
||||||
|
|
||||||
#include "ethernet_layer.hpp"
|
#include "ethernet_layer.hpp"
|
||||||
|
|
||||||
@ -26,11 +28,15 @@
|
|||||||
#define RX_BUF_PTR 0x38
|
#define RX_BUF_PTR 0x38
|
||||||
#define RX_BUF_ADDR 0x3A
|
#define RX_BUF_ADDR 0x3A
|
||||||
|
|
||||||
|
#define TX_STATUS 0x10 // First TX status register (32 bit)
|
||||||
|
#define TX_ADDR 0x20 // First Tx Address register (32 bit)
|
||||||
|
|
||||||
#define RX_MISSED 0x4C
|
#define RX_MISSED 0x4C
|
||||||
#define CMD_NOT_EMPTY 0x01
|
#define CMD_NOT_EMPTY 0x01
|
||||||
|
|
||||||
#define RX_OK 0x01
|
#define RX_OK 0x01 // Receive OK
|
||||||
#define TX_OK 0x04
|
#define TX_OK 0x04 // Transmit OK
|
||||||
|
#define TX_ERR 0x08 // Transmit error
|
||||||
|
|
||||||
#define RCR_AAP (1 << 0) /* Accept All Packets */
|
#define RCR_AAP (1 << 0) /* Accept All Packets */
|
||||||
#define RCR_APM (1 << 1) /* Accept Physical Match Packets */
|
#define RCR_APM (1 << 1) /* Accept Physical Match Packets */
|
||||||
@ -48,21 +54,39 @@
|
|||||||
#define RX_PHYSICAL 0x4000
|
#define RX_PHYSICAL 0x4000
|
||||||
#define RX_MULTICAST 0x8000
|
#define RX_MULTICAST 0x8000
|
||||||
|
|
||||||
|
#define TX_STATUS_HOST_OWNS 0x00002000
|
||||||
|
#define TX_STATUS_UNDERRUN 0x00004000
|
||||||
|
#define TX_STATUS_OK 0x00008000
|
||||||
|
#define TX_STATUS_OUT_OF_WINDOW 0x20000000
|
||||||
|
#define TX_STATUS_ABORTED 0x40000000
|
||||||
|
#define TX_STATUS_CARRIER_LOST 0x80000000
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr const size_t tx_buffers = 4;
|
||||||
|
constexpr const size_t tx_buffer_size = 0x2000;
|
||||||
|
|
||||||
|
struct tx_desc_t {
|
||||||
|
size_t buffer_phys;
|
||||||
|
size_t buffer_virt;
|
||||||
|
};
|
||||||
|
|
||||||
struct rtl8139_t {
|
struct rtl8139_t {
|
||||||
uint32_t iobase;
|
uint32_t iobase;
|
||||||
uint64_t phys_buffer_rx;
|
uint64_t phys_buffer_rx;
|
||||||
uint64_t buffer_rx;
|
uint64_t buffer_rx;
|
||||||
|
|
||||||
uint64_t cur_rx; //Index inside the buffer
|
uint64_t cur_rx; //Index inside the receive buffer
|
||||||
|
volatile uint64_t cur_tx; //Index inside the transmit buffer
|
||||||
|
volatile uint64_t dirty_tx; //Index inside the transmit buffer
|
||||||
|
|
||||||
|
tx_desc_t tx_desc[tx_buffers];
|
||||||
|
semaphore tx_sem;
|
||||||
|
|
||||||
network::interface_descriptor* interface;
|
network::interface_descriptor* interface;
|
||||||
};
|
};
|
||||||
|
|
||||||
void packet_handler(interrupt::syscall_regs*, void* data){
|
void packet_handler(interrupt::syscall_regs*, void* data){
|
||||||
logging::logf(logging::log_level::TRACE, "rtl8139: Packet Received\n");
|
|
||||||
|
|
||||||
auto& desc = *static_cast<rtl8139_t*>(data);
|
auto& desc = *static_cast<rtl8139_t*>(data);
|
||||||
|
|
||||||
// Get the interrupt status
|
// Get the interrupt status
|
||||||
@ -72,7 +96,7 @@ void packet_handler(interrupt::syscall_regs*, void* data){
|
|||||||
out_word(desc.iobase + ISR, status);
|
out_word(desc.iobase + ISR, status);
|
||||||
|
|
||||||
if(status & RX_OK){
|
if(status & RX_OK){
|
||||||
logging::logf(logging::log_level::TRACE, "rtl8139: Receive status OK\n");
|
logging::logf(logging::log_level::TRACE, "rtl8139: Packet received correctly OK\n");
|
||||||
|
|
||||||
auto cur_rx = desc.cur_rx;
|
auto cur_rx = desc.cur_rx;
|
||||||
|
|
||||||
@ -114,8 +138,41 @@ void packet_handler(interrupt::syscall_regs*, void* data){
|
|||||||
}
|
}
|
||||||
|
|
||||||
desc.cur_rx = cur_rx;
|
desc.cur_rx = cur_rx;
|
||||||
|
} else if(status & (TX_OK | TX_ERR)){
|
||||||
|
auto& dirty_tx = desc.dirty_tx;
|
||||||
|
size_t cleaned_up = 0;
|
||||||
|
|
||||||
|
while(desc.cur_tx - dirty_tx > 0){
|
||||||
|
auto entry = dirty_tx % tx_buffers;
|
||||||
|
|
||||||
|
auto tx_status = in_dword(desc.iobase + TX_STATUS + entry * 4);
|
||||||
|
|
||||||
|
// Check if the packet has already been transmitted
|
||||||
|
if(!(tx_status & (TX_STATUS_OK | TX_STATUS_ABORTED | TX_STATUS_UNDERRUN))){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(tx_status & (TX_STATUS_OUT_OF_WINDOW | TX_STATUS_ABORTED)){
|
||||||
|
if(tx_status & TX_STATUS_CARRIER_LOST){
|
||||||
|
logging::logf(logging::log_level::ERROR, "rtl8139: Carrier lost\n");
|
||||||
|
} else if (tx_status & TX_STATUS_OUT_OF_WINDOW){
|
||||||
|
logging::logf(logging::log_level::ERROR, "rtl8139: Out of window\n");
|
||||||
|
} else {
|
||||||
|
logging::logf(logging::log_level::TRACE, "rtl8139: Packet abortd\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logging::logf(logging::log_level::TRACE, "rtl8139: Packet transmitted correctly\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
++cleaned_up;
|
||||||
|
++dirty_tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc.tx_sem.release(cleaned_up);
|
||||||
} else {
|
} else {
|
||||||
logging::logf(logging::log_level::TRACE, "rtl8139: Receive status not OK\n");
|
// This should not happen since we only enable a few
|
||||||
|
// interrupts
|
||||||
|
logging::logf(logging::log_level::ERROR, "rtl8139: Receive status unhandled OK\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,8 +180,22 @@ void send_packet(const network::interface_descriptor& interface, network::ethern
|
|||||||
logging::logf(logging::log_level::TRACE, "rtl8139: Start transmitting packet\n");
|
logging::logf(logging::log_level::TRACE, "rtl8139: Start transmitting packet\n");
|
||||||
|
|
||||||
auto& desc = *reinterpret_cast<rtl8139_t*>(interface.driver_data);
|
auto& desc = *reinterpret_cast<rtl8139_t*>(interface.driver_data);
|
||||||
|
auto iobase = desc.iobase;
|
||||||
|
|
||||||
//TODO
|
// Wait for a free entry in the tx buffers
|
||||||
|
desc.tx_sem.acquire();
|
||||||
|
|
||||||
|
// Claim an entry in the tx buffers
|
||||||
|
auto entry = __sync_fetch_and_add(&desc.cur_tx, 1) % tx_buffers;
|
||||||
|
|
||||||
|
auto& tx_desc = desc.tx_desc[entry];
|
||||||
|
|
||||||
|
std::copy_n(reinterpret_cast<char*>(tx_desc.buffer_virt), packet.payload, packet.payload_size);
|
||||||
|
|
||||||
|
out_dword(iobase + TX_ADDR + entry * 4, tx_desc.buffer_phys);
|
||||||
|
out_dword(iobase + TX_STATUS + entry * 4, uint32_t(256) << 16 | packet.payload_size);
|
||||||
|
|
||||||
|
delete[] packet.payload; //TODO Probably not the base place
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end of anonymous namespace
|
} //end of anonymous namespace
|
||||||
@ -138,6 +209,19 @@ void rtl8139::init_driver(network::interface_descriptor& interface, pci::device_
|
|||||||
interface.driver_data = desc;
|
interface.driver_data = desc;
|
||||||
interface.hw_send = send_packet;
|
interface.hw_send = send_packet;
|
||||||
|
|
||||||
|
desc->tx_sem.init(tx_buffers);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < tx_buffers; ++i){
|
||||||
|
auto& tx_desc = desc->tx_desc[i];
|
||||||
|
|
||||||
|
tx_desc.buffer_phys = physical_allocator::allocate(2);
|
||||||
|
tx_desc.buffer_virt = virtual_allocator::allocate(2);
|
||||||
|
|
||||||
|
if(!paging::map_pages(tx_desc.buffer_virt, tx_desc.buffer_phys, 2)){
|
||||||
|
logging::logf(logging::log_level::ERROR, "rtl8139: Unable to map %h into %h\n", tx_desc.buffer_virt, tx_desc.buffer_phys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Enable PCI Bus Mastering (allows DMA)
|
// 1. Enable PCI Bus Mastering (allows DMA)
|
||||||
|
|
||||||
auto command_register = pci::read_config_dword(pci_device.bus, pci_device.device, pci_device.function, 0x4);
|
auto command_register = pci::read_config_dword(pci_device.bus, pci_device.device, pci_device.function, 0x4);
|
||||||
@ -175,6 +259,8 @@ void rtl8139::init_driver(network::interface_descriptor& interface, pci::device_
|
|||||||
desc->phys_buffer_rx = buffer_rx_phys;
|
desc->phys_buffer_rx = buffer_rx_phys;
|
||||||
desc->buffer_rx = buffer_rx_virt;
|
desc->buffer_rx = buffer_rx_virt;
|
||||||
desc->cur_rx = 0;
|
desc->cur_rx = 0;
|
||||||
|
desc->cur_tx = 0;
|
||||||
|
desc->dirty_tx = 0;
|
||||||
|
|
||||||
std::fill_n(reinterpret_cast<char*>(desc->buffer_rx), 0x3000, 0);
|
std::fill_n(reinterpret_cast<char*>(desc->buffer_rx), 0x3000, 0);
|
||||||
|
|
||||||
@ -191,7 +277,7 @@ void rtl8139::init_driver(network::interface_descriptor& interface, pci::device_
|
|||||||
logging::logf(logging::log_level::TRACE, "rtl8139: IRQ :%u\n", uint64_t(irq));
|
logging::logf(logging::log_level::TRACE, "rtl8139: IRQ :%u\n", uint64_t(irq));
|
||||||
|
|
||||||
// Enable some interrupts
|
// Enable some interrupts
|
||||||
out_word(iobase + IMR, TX_OK | RX_OK);
|
out_word(iobase + IMR, RX_OK | TX_OK | TX_ERR);
|
||||||
|
|
||||||
// 8. Set RCR (Receive Configuration Register)
|
// 8. Set RCR (Receive Configuration Register)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user