113 lines
3.4 KiB
C
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);
|
|
}
|