Cleanup E1000 driver and read MAC from MMIO for Qemu.

This commit is contained in:
Ali Mashtizadeh 2023-11-24 17:00:05 -05:00
parent f7c3993e2d
commit 4b926b6ca9
2 changed files with 59 additions and 18 deletions

View File

@ -24,6 +24,8 @@ typedef struct E1000Device
static E1000Device deviceList[] =
{
{ 0x8086100e, "E1000", 0 }, // EERD is not supported
{ 0x808610c9, "IGB", 0 },
{ 0x808610d3, "E1000E", 0 },
// { 0x80861209, "i82551", 0 }, // Doesn't seem to work on my qemu build
{ 0, "", 0 },
};
@ -62,6 +64,22 @@ void E1000_Configure(PCIDevice dev);
#define E1000_REG_MTABASE 0x5200
#define E1000_REG_RAL 0x5400
#define E1000_REG_RAH 0x5404
// EEPROM Control and Data Register
#define EE_SK (1 << 0)
#define EE_CS (1 << 1)
#define EE_DI (1 << 2)
#define EE_DO (1 << 3)
// FWE (Flash Write Enable) 5:4
#define EE_REQ (1 << 6)
#define EE_GNT (1 << 7)
#define EE_PRES (1 << 8)
#define EE_SIZE (1 << 9)
#define EE_SIZE2 (1 << 10)
#define EE_TYPE (1 << 13)
// EEPROM Offsets
#define NVM_MAC_ADDR 0x0000
#define NVM_DEVICE_ID 0x000D
@ -180,7 +198,7 @@ E1000_Init(uint32_t bus, uint32_t slot, uint32_t func)
int deviceIdx = 0;
while (deviceList[deviceIdx].device != 0x0) {
if (deviceList[deviceIdx].device == device) {
kprintf("E1000: Found %s\n", deviceList[deviceIdx].name);
Log(e1000, "Found %s\n", deviceList[deviceIdx].name);
// Configure and add disks
E1000_Configure(dev);
}
@ -198,7 +216,7 @@ MMIO_Read32(E1000Dev *dev, uint64_t addr)
static inline void
MMIO_Write32(E1000Dev *dev, uint64_t addr, uint32_t val)
{
*(uint32_t *)(dev->mmiobase + addr) = val;
*(uint32_t volatile *)(dev->mmiobase + addr) = val;
}
static uint16_t
@ -206,6 +224,13 @@ E1000_EEPROM_Read(E1000Dev *dev, uint8_t addr)
{
uint16_t val;
uint32_t eecd = MMIO_Read32(dev, E1000_REG_EECD);
MMIO_Write32(dev, E1000_REG_EECD, eecd & ~(EE_REQ|EE_GNT));
if (!(eecd & EE_PRES)) {
DLOG(e1000, "EEPROM Not Present!\n");
return 0;
}
// Write Address
MMIO_Write32(dev, E1000_REG_EERD, ((uint32_t)addr << 8) | 1);
@ -216,7 +241,7 @@ E1000_EEPROM_Read(E1000Dev *dev, uint8_t addr)
break;
}
kprintf("%08x\n", val);
DLOG(e1000, "EEPROM 0x%02x = %08x\n", addr, val);
return (uint16_t)((val >> 16) & 0x0000FFFF);
}
@ -225,7 +250,7 @@ void
E1000_TXPoll(E1000Dev *dev)
{
// Free memory
kprintf("TXPOLL\n");
Log(e1000, "TXPOLL\n");
}
void
@ -249,8 +274,8 @@ E1000_RXPoll(E1000Dev *dev)
}
if (dev->rxDesc[dev->rxTail].errors) {
kprintf("E1000: Error in RX Queue %x\n",
dev->rxDesc[dev->rxTail].errors);
Alert(e1000, "Error in RX Queue %x\n",
dev->rxDesc[dev->rxTail].errors);
dev->rxDesc[dev->rxTail].status = 0;
dev->rxDesc[dev->rxTail].errors = 0;
MMIO_Write32(dev, E1000_REG_RDT, dev->rxTail);
@ -272,8 +297,8 @@ E1000_Interrupt(void *arg)
{
E1000Dev *dev = (E1000Dev *)arg;
kprintf("E1000 (%d:%d) Interrupt\n",
dev->dev.bus, dev->dev.slot);
DLOG(e1000, "Interrupt (%d:%d)\n",
dev->dev.bus, dev->dev.slot);
uint32_t cause = MMIO_Read32(dev, E1000_REG_ICR);
@ -292,7 +317,7 @@ E1000_Interrupt(void *arg)
// Receive Overrun
if (cause & ICR_RXO) {
cause &= ~ICR_RXO;
kprintf("underrun %u %u\n", MMIO_Read32(dev, E1000_REG_RDH), dev->rxTail);
DLOG(e1000, "underrun %u %u\n", MMIO_Read32(dev, E1000_REG_RDH), dev->rxTail);
E1000_RXPoll(dev);
}
@ -304,7 +329,7 @@ E1000_Interrupt(void *arg)
}
if (cause != 0) {
kprintf("E1000: Unhandled cause %08x\n", cause);
Alert(e1000, "Unhandled cause %08x\n", cause);
}
MMIO_Read32(dev, E1000_REG_ICR);
@ -460,9 +485,9 @@ E1000_Configure(PCIDevice dev)
if (dev.bars[bar].size == 0)
continue;
kprintf("E1000: BAR%d base=%08x size=%08x %s\n",
bar, dev.bars[bar].base, dev.bars[bar].size,
dev.bars[bar].type == PCIBAR_TYPE_IO ? "IO" : "Mem");
Log(e1000, "BAR%d base=%08x size=%08x %s\n",
bar, dev.bars[bar].base, dev.bars[bar].size,
dev.bars[bar].type == PCIBAR_TYPE_IO ? "IO" : "Mem");
}
ethDev->mmiobase = (uint8_t *)DMPA2VA(dev.bars[0].base);
@ -471,16 +496,31 @@ E1000_Configure(PCIDevice dev)
MMIO_Write32(ethDev, E1000_REG_CTRL, MMIO_Read32(ethDev, E1000_REG_CTRL) | CTRL_SLU);
// Register IRQs
kprintf("E1000: IRQ %d\n", dev.irq);
Log(e1000, "IRQ %d\n", dev.irq);
ethDev->irqHandle.irq = dev.irq;
ethDev->irqHandle.cb = &E1000_Interrupt;
ethDev->irqHandle.arg = ethDev;
IRQ_Register(dev.irq, &ethDev->irqHandle);
kprintf("E1000: MAC XX:XX:XX:XX:XX:XX\n");
// EEPROM's are really supported on Qemu or Virtualbox
for (int i = 0; i < 3; i++) {
E1000_EEPROM_Read(ethDev, NVM_MAC_ADDR + 2*i);
}
uint32_t ral = MMIO_Read32(ethDev, E1000_REG_RAL);
uint32_t rah = MMIO_Read32(ethDev, E1000_REG_RAH);
ethDev->nic.mac[0] = ral & 0xff;
ethDev->nic.mac[1] = (ral >> 8) & 0xff;
ethDev->nic.mac[2] = (ral >> 16) & 0xff;
ethDev->nic.mac[3] = (ral >> 24) & 0xff;
ethDev->nic.mac[4] = rah & 0xff;
ethDev->nic.mac[5] = (rah >> 8) & 0xff;
Log(e1000, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
ethDev->nic.mac[0], ethDev->nic.mac[1],
ethDev->nic.mac[2], ethDev->nic.mac[3],
ethDev->nic.mac[4], ethDev->nic.mac[5]);
// Device lock
Spinlock_Init(&ethDev->lock, "E1000 Spinlock", SPINLOCK_TYPE_NORMAL);

View File

@ -24,11 +24,12 @@
SYSCTL_STR(kern_ostype, SYSCTL_FLAG_RO, "OS Type", "Castor") \
SYSCTL_INT(kern_hz, SYSCTL_FLAG_RW, "Tick frequency", 100) \
SYSCTL_INT(time_tzadj, SYSCTL_FLAG_RW, "Time zone offset in seconds", 0) \
SYSCTL_INT(log_syscall, SYSCTL_FLAG_RW, "Syscall log level", 0) \
SYSCTL_INT(log_e1000, SYSCTL_FLAG_RW, "E1000 log level", 10) \
SYSCTL_INT(log_ide, SYSCTL_FLAG_RW, "IDE log level", 0) \
SYSCTL_INT(log_loader, SYSCTL_FLAG_RW, "Loader log level", 0) \
SYSCTL_INT(log_vfs, SYSCTL_FLAG_RW, "VFS log level", 0) \
SYSCTL_INT(log_o2fs, SYSCTL_FLAG_RW, "O2FS log level", 0) \
SYSCTL_INT(log_ide, SYSCTL_FLAG_RW, "IDE log level", 0)
SYSCTL_INT(log_syscall, SYSCTL_FLAG_RW, "Syscall log level", 0) \
SYSCTL_INT(log_vfs, SYSCTL_FLAG_RW, "VFS log level", 0)
#define SYSCTL_STR_MAXLENGTH 128