Files
nt-lite/code/drivers/net/rtl8139/rtl8139_pci.c
T

113 lines
3.4 KiB
C

// rtl8139_pci.c - PCI BAR/MMIO front-end for rtl8139.
#include "rtl8139.h"
bool Rtl8139ReadBar(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t index, RTL8139_BAR* out) {
uint8_t reg = (uint8_t)(PCI_REG_BAR0 + index * 4u);
uint32_t lo = gHal->Pci.Read32(bus, dev, fn, reg);
out->Kind = Rtl8139BarNone;
out->Base = 0;
out->Index = index;
if (lo == 0 || lo == 0xFFFFFFFFu)
return false;
if (lo & 1u) {
uint32_t base = lo & ~0x3u;
if (!base) return false;
out->Kind = Rtl8139BarIo;
out->Base = base;
return true;
}
uint64_t base = (uint64_t)(lo & ~0xFu);
uint32_t type = (lo >> 1) & 0x3u;
if (type == 0x2u && index < 5) {
uint32_t hi = gHal->Pci.Read32(bus, dev, fn, (uint8_t)(reg + 4u));
base |= ((uint64_t)hi << 32);
}
if (!base) return false;
out->Kind = Rtl8139BarMmio;
out->Base = base;
return true;
}
KSTATUS Rtl8139MapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
uint64_t pageBase = physBase & PAGE_MASK;
uint64_t pageOff = physBase - pageBase;
for (uint32_t i = 0; i < RTL8139_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys);
KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st))
return st;
}
*outMmio = (volatile uint8_t*)((uintptr_t)gHal->PhysToVirt(pageBase) + pageOff);
return STATUS_SUCCESS;
}
KSTATUS Rtl8139SelectRegisterBar(RTL8139_DEVICE* r) {
RTL8139_BAR best = { Rtl8139BarNone, 0, 0 };
RTL8139_BAR fallback = { Rtl8139BarNone, 0, 0 };
for (uint8_t i = 0; i < 6; i++) {
RTL8139_BAR bar;
if (!Rtl8139ReadBar(r->Bus, r->Dev, r->Fn, i, &bar))
continue;
if (bar.Kind == Rtl8139BarMmio) {
best = bar;
break;
}
if (bar.Kind == Rtl8139BarIo && fallback.Kind == Rtl8139BarNone)
fallback = bar;
if (bar.Kind == Rtl8139BarMmio) {
uint32_t lo = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, (uint8_t)(PCI_REG_BAR0 + i * 4u));
if (((lo >> 1) & 0x3u) == 0x2u)
i++;
}
}
if (best.Kind == Rtl8139BarNone)
best = fallback;
if (best.Kind == Rtl8139BarMmio) {
KSTATUS st = Rtl8139MapMmio(best.Base, &r->Mmio);
if (!KSUCCESS(st))
return st;
r->UseMmio = true;
DbgPrint("RTL8139: BAR%u MMIO base=0x%016llX virt=0x%016llX\n",
best.Index, (unsigned long long)best.Base, r->Mmio);
return STATUS_SUCCESS;
}
if (best.Kind == Rtl8139BarIo) {
if (best.Base > 0xFFFFu)
return STATUS_NOT_SUPPORTED;
r->IoBase = (uint16_t)best.Base;
r->UseMmio = false;
DbgPrint("RTL8139: BAR%u I/O base=0x%04x\n", best.Index, r->IoBase);
return STATUS_SUCCESS;
}
return STATUS_NOT_FOUND;
}
void Rtl8139EnablePci(RTL8139_DEVICE* r) {
uint32_t cmd = gHal->Pci.Read32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND);
cmd |= PCI_COMMAND_MASTER;
if (r->UseMmio) cmd |= PCI_COMMAND_MEMORY;
else cmd |= PCI_COMMAND_IO;
cmd &= ~PCI_COMMAND_INTX_DISABLE;
gHal->Pci.Write32(r->Bus, r->Dev, r->Fn, PCI_REG_COMMAND, cmd);
}