mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
253 lines
7.4 KiB
C
253 lines
7.4 KiB
C
#include <drivers/e1000.h>
|
|
#include <drivers/pci.h>
|
|
#include <net/net.h>
|
|
#include <mm/kmalloc.h>
|
|
#include <mm/pmm.h>
|
|
#include <arch/x86_64/isr.h>
|
|
#include <arch/x86_64/pic.h>
|
|
#include <arch/x86_64/io.h>
|
|
#include <lib/string.h>
|
|
#include <kernel/printk.h>
|
|
|
|
#define REG_CTRL 0x0000
|
|
#define REG_STATUS 0x0008
|
|
#define REG_EEPROM 0x0014
|
|
#define REG_ICR 0x00C0
|
|
#define REG_IMS 0x00D0
|
|
#define REG_IMC 0x00D8
|
|
#define REG_RCTL 0x0100
|
|
#define REG_RDBAL 0x2800
|
|
#define REG_RDBAH 0x2804
|
|
#define REG_RDLEN 0x2808
|
|
#define REG_RDH 0x2810
|
|
#define REG_RDT 0x2818
|
|
#define REG_TCTL 0x0400
|
|
#define REG_TDBAL 0x3800
|
|
#define REG_TDBAH 0x3804
|
|
#define REG_TDLEN 0x3808
|
|
#define REG_TDH 0x3810
|
|
#define REG_TDT 0x3818
|
|
|
|
#define NUM_RX_DESCRIPTORS 32
|
|
#define NUM_TX_DESCRIPTORS 16
|
|
#define RX_BUFFER_SIZE 2048
|
|
|
|
typedef struct {
|
|
uint64_t buffer_addr;
|
|
uint16_t length;
|
|
uint16_t checksum;
|
|
uint8_t status;
|
|
uint8_t errors;
|
|
uint16_t special;
|
|
} __attribute__((packed)) e1000_rx_desc_t;
|
|
|
|
typedef struct {
|
|
uint64_t buffer_addr;
|
|
uint16_t length;
|
|
uint8_t cso;
|
|
uint8_t cmd;
|
|
uint8_t status;
|
|
uint8_t css;
|
|
uint16_t special;
|
|
} __attribute__((packed)) e1000_tx_desc_t;
|
|
|
|
static pci_device_t* e1000_pci_dev = NULL;
|
|
static uint64_t mmio_base = 0;
|
|
static uint16_t io_base = 0;
|
|
static bool use_mmio = true;
|
|
static uint8_t mac_addr[6] = {0x52, 0x54, 0x00, 0x12, 0x34, 0x56};
|
|
|
|
static e1000_rx_desc_t* rx_descriptors = NULL;
|
|
static uint8_t* rx_buffers[NUM_RX_DESCRIPTORS];
|
|
static uint16_t rx_cur = 0;
|
|
|
|
static e1000_tx_desc_t* tx_descriptors = NULL;
|
|
static uint8_t* tx_buffers[NUM_TX_DESCRIPTORS];
|
|
static uint16_t tx_cur = 0;
|
|
|
|
static uint64_t stats_rx_packets = 0;
|
|
static uint64_t stats_tx_packets = 0;
|
|
static uint64_t stats_rx_bytes = 0;
|
|
static uint64_t stats_tx_bytes = 0;
|
|
|
|
static inline void e1000_write32(uint32_t reg, uint32_t val) {
|
|
if (use_mmio && mmio_base) {
|
|
*((volatile uint32_t*)(mmio_base + reg)) = val;
|
|
} else if (io_base) {
|
|
outl(io_base, reg);
|
|
outl(io_base + 4, val);
|
|
}
|
|
}
|
|
|
|
static inline uint32_t e1000_read32(uint32_t reg) {
|
|
if (use_mmio && mmio_base) {
|
|
return *((volatile uint32_t*)(mmio_base + reg));
|
|
} else if (io_base) {
|
|
outl(io_base, reg);
|
|
return inl(io_base + 4);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void e1000_read_mac(void) {
|
|
uint32_t ral = e1000_read32(0x5400);
|
|
uint32_t rah = e1000_read32(0x5404);
|
|
|
|
if (ral != 0 || (rah & 0xFFFF) != 0) {
|
|
mac_addr[0] = ral & 0xFF;
|
|
mac_addr[1] = (ral >> 8) & 0xFF;
|
|
mac_addr[2] = (ral >> 16) & 0xFF;
|
|
mac_addr[3] = (ral >> 24) & 0xFF;
|
|
mac_addr[4] = rah & 0xFF;
|
|
mac_addr[5] = (rah >> 8) & 0xFF;
|
|
}
|
|
}
|
|
|
|
static void e1000_handle_receive(void) {
|
|
while (rx_descriptors[rx_cur].status & 0x01) {
|
|
uint16_t len = rx_descriptors[rx_cur].length;
|
|
uint8_t* buf = rx_buffers[rx_cur];
|
|
|
|
stats_rx_packets++;
|
|
stats_rx_bytes += len;
|
|
|
|
// Forward to network stack
|
|
net_receive(buf, len);
|
|
|
|
rx_descriptors[rx_cur].status = 0;
|
|
uint16_t old_cur = rx_cur;
|
|
rx_cur = (rx_cur + 1) % NUM_RX_DESCRIPTORS;
|
|
e1000_write32(REG_RDT, old_cur);
|
|
}
|
|
}
|
|
|
|
static void e1000_interrupt_handler(registers_t* regs) {
|
|
(void)regs;
|
|
uint32_t icr = e1000_read32(REG_ICR);
|
|
|
|
if (icr & 0x80) {
|
|
e1000_handle_receive();
|
|
}
|
|
if (icr & 0x04) {
|
|
printk(KERN_INFO "[E1000] Link status changed: %s\n", e1000_is_link_up() ? "UP" : "DOWN");
|
|
}
|
|
}
|
|
|
|
static void e1000_init_rx(void) {
|
|
rx_descriptors = (e1000_rx_desc_t*)kzalloc(sizeof(e1000_rx_desc_t) * NUM_RX_DESCRIPTORS + 16);
|
|
rx_descriptors = (e1000_rx_desc_t*)(((uint64_t)rx_descriptors + 15) & ~15);
|
|
|
|
for (int i = 0; i < NUM_RX_DESCRIPTORS; i++) {
|
|
rx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
|
|
rx_descriptors[i].buffer_addr = (uint64_t)rx_buffers[i];
|
|
rx_descriptors[i].status = 0;
|
|
}
|
|
|
|
uint64_t rx_desc_phys = (uint64_t)rx_descriptors;
|
|
e1000_write32(REG_RDBAL, (uint32_t)(rx_desc_phys & 0xFFFFFFFF));
|
|
e1000_write32(REG_RDBAH, (uint32_t)(rx_desc_phys >> 32));
|
|
e1000_write32(REG_RDLEN, NUM_RX_DESCRIPTORS * sizeof(e1000_rx_desc_t));
|
|
e1000_write32(REG_RDH, 0);
|
|
e1000_write32(REG_RDT, NUM_RX_DESCRIPTORS - 1);
|
|
rx_cur = 0;
|
|
|
|
// RCTL: Enable, Broadcast, Strip CRC, Multicast
|
|
e1000_write32(REG_RCTL, (1 << 1) | (1 << 15) | (1 << 26) | (1 << 4));
|
|
}
|
|
|
|
static void e1000_init_tx(void) {
|
|
tx_descriptors = (e1000_tx_desc_t*)kzalloc(sizeof(e1000_tx_desc_t) * NUM_TX_DESCRIPTORS + 16);
|
|
tx_descriptors = (e1000_tx_desc_t*)(((uint64_t)tx_descriptors + 15) & ~15);
|
|
|
|
for (int i = 0; i < NUM_TX_DESCRIPTORS; i++) {
|
|
tx_buffers[i] = (uint8_t*)kmalloc(RX_BUFFER_SIZE + 16);
|
|
tx_descriptors[i].buffer_addr = (uint64_t)tx_buffers[i];
|
|
tx_descriptors[i].status = 1;
|
|
tx_descriptors[i].cmd = 0;
|
|
}
|
|
|
|
uint64_t tx_desc_phys = (uint64_t)tx_descriptors;
|
|
e1000_write32(REG_TDBAL, (uint32_t)(tx_desc_phys & 0xFFFFFFFF));
|
|
e1000_write32(REG_TDBAH, (uint32_t)(tx_desc_phys >> 32));
|
|
e1000_write32(REG_TDLEN, NUM_TX_DESCRIPTORS * sizeof(e1000_tx_desc_t));
|
|
e1000_write32(REG_TDH, 0);
|
|
e1000_write32(REG_TDT, 0);
|
|
tx_cur = 0;
|
|
|
|
// TCTL: Enable, Pad Short Packets, Collisions
|
|
e1000_write32(REG_TCTL, (1 << 1) | (1 << 3) | (0x0F << 4) | (0x40 << 12));
|
|
}
|
|
|
|
bool e1000_init(void) {
|
|
e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82540EM);
|
|
if (!e1000_pci_dev) e1000_pci_dev = pci_find_device(E1000_VENDOR_ID, E1000_DEV_82545EM);
|
|
if (!e1000_pci_dev) e1000_pci_dev = pci_find_class(PCI_CLASS_NETWORK, PCI_SUBCLASS_ETHERNET);
|
|
|
|
if (!e1000_pci_dev) {
|
|
return false;
|
|
}
|
|
|
|
pci_enable_bus_mastering(e1000_pci_dev);
|
|
|
|
if (e1000_pci_dev->bar_type[0] == 0 && e1000_pci_dev->bar[0] != 0) {
|
|
mmio_base = e1000_pci_dev->bar[0] & ~0xF;
|
|
use_mmio = true;
|
|
} else {
|
|
io_base = (uint16_t)(e1000_pci_dev->bar[1] & ~0x3);
|
|
use_mmio = false;
|
|
}
|
|
|
|
e1000_read_mac();
|
|
|
|
uint8_t irq = e1000_pci_dev->irq;
|
|
if (irq > 0 && irq <= 15) {
|
|
isr_register_handler(32 + irq, e1000_interrupt_handler);
|
|
pic_clear_mask(irq);
|
|
}
|
|
|
|
e1000_init_rx();
|
|
e1000_init_tx();
|
|
|
|
e1000_write32(REG_IMS, (1 << 7) | (1 << 4) | (1 << 6) | (1 << 2));
|
|
e1000_read32(REG_ICR);
|
|
|
|
printk(KERN_INFO "[E1000] Initialized. MAC: %02x:%02x:%02x:%02x:%02x:%02x (IRQ %d)\n",
|
|
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], irq);
|
|
return true;
|
|
}
|
|
|
|
void e1000_send(const void* data, uint16_t len) {
|
|
if (!data || len == 0) return;
|
|
|
|
while (!(tx_descriptors[tx_cur].status & 0x01)) {
|
|
io_wait();
|
|
}
|
|
|
|
memcpy(tx_buffers[tx_cur], data, len);
|
|
tx_descriptors[tx_cur].length = len;
|
|
tx_descriptors[tx_cur].cmd = (1 << 0) | (1 << 1) | (1 << 3); // EOP, RS, IFCS
|
|
tx_descriptors[tx_cur].status = 0;
|
|
|
|
tx_cur = (tx_cur + 1) % NUM_TX_DESCRIPTORS;
|
|
stats_tx_packets++;
|
|
stats_tx_bytes += len;
|
|
|
|
e1000_write32(REG_TDT, tx_cur);
|
|
}
|
|
|
|
void e1000_get_mac(uint8_t* mac_out) {
|
|
if (mac_out) {
|
|
memcpy(mac_out, mac_addr, 6);
|
|
}
|
|
}
|
|
|
|
bool e1000_is_link_up(void) {
|
|
uint32_t status = e1000_read32(REG_STATUS);
|
|
return (status & (1 << 1)) != 0;
|
|
}
|
|
|
|
uint64_t e1000_get_rx_packets(void) { return stats_rx_packets; }
|
|
uint64_t e1000_get_tx_packets(void) { return stats_tx_packets; }
|
|
uint64_t e1000_get_rx_bytes(void) { return stats_rx_bytes; }
|
|
uint64_t e1000_get_tx_bytes(void) { return stats_tx_bytes; }
|