提交 dfa9c79c 创建 作者: Silas Boyd-Wickizer's avatar Silas Boyd-Wickizer

First complete pass at e1000.

All our machines, however, have e1000e cards.
上级 7ab0d619
...@@ -45,6 +45,7 @@ OBJS = \ ...@@ -45,6 +45,7 @@ OBJS = \
main.o \ main.o \
memide.o \ memide.o \
mp.o \ mp.o \
net.o \
ns.o \ ns.o \
pci.o \ pci.o \
picirq.o \ picirq.o \
...@@ -142,7 +143,9 @@ $(O)/mscan.kern: $(O)/kernel ...@@ -142,7 +143,9 @@ $(O)/mscan.kern: $(O)/kernel
## ##
## qemu ## qemu
## ##
QEMUOPTS = -smp $(QEMUSMP) -m 512 -serial mon:stdio -nographic QEMUOPTS = -smp $(QEMUSMP) -m 512 -serial mon:stdio -nographic \
-net user -net nic,model=e1000 \
-net dump,file=qemu.pcap
qemu: $(O)/kernel qemu: $(O)/kernel
$(QEMU) $(QEMUOPTS) -kernel $(O)/kernel $(QEMU) $(QEMUOPTS) -kernel $(O)/kernel
......
...@@ -4,22 +4,36 @@ ...@@ -4,22 +4,36 @@
#include "pci.h" #include "pci.h"
#include "e1000reg.h" #include "e1000reg.h"
#define TX_RING_SIZE 64
#define RX_RING_SIZE 64
int e1000irq;
static struct { static struct {
u32 membase; u32 membase;
u32 iobase; u32 iobase;
u16 pcidevid; u16 pcidevid;
u32 txclean;
u32 txinuse;
u32 rxclean;
u32 rxuse;
struct wiseman_txdesc txd[TX_RING_SIZE] __attribute__((aligned (16)));
struct wiseman_rxdesc rxd[RX_RING_SIZE] __attribute__((aligned (16)));
} e1000; } e1000;
static u32 static inline u32
e1000_io_read(u32 reg) erd(u32 reg)
{ {
paddr pa = e1000.membase + reg; paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa); volatile u32 *ptr = p2v(pa);
return *ptr; return *ptr;
} }
static void static inline void
e1000_io_write(u32 reg, u32 val) ewr(u32 reg, u32 val)
{ {
paddr pa = e1000.membase + reg; paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa); volatile u32 *ptr = p2v(pa);
...@@ -33,9 +47,9 @@ eeprom_eerd_read(u16 off) ...@@ -33,9 +47,9 @@ eeprom_eerd_read(u16 off)
int x; int x;
// [E1000 5.3.1] Software EEPROM access // [E1000 5.3.1] Software EEPROM access
e1000_io_write(WMREG_EERD, (off<<EERD_ADDR_SHIFT) | EERD_START); ewr(WMREG_EERD, (off<<EERD_ADDR_SHIFT) | EERD_START);
for (x = 0; x < 100; x++) { for (x = 0; x < 5; x++) {
reg = e1000_io_read(WMREG_EERD); reg = erd(WMREG_EERD);
if (reg & EERD_DONE) if (reg & EERD_DONE)
return (reg&EERD_DATA_MASK) >> EERD_DATA_SHIFT; return (reg&EERD_DATA_MASK) >> EERD_DATA_SHIFT;
microdelay(50000); microdelay(50000);
...@@ -58,6 +72,176 @@ eeprom_read(u16 *buf, int off, int count) ...@@ -58,6 +72,176 @@ eeprom_read(u16 *buf, int off, int count)
} }
int int
e1000tx(void *buf, u32 len)
{
struct wiseman_txdesc *desc;
u32 tail;
// WMREG_TDT should only equal WMREG_TDH when we have
// nothing to transmit. Therefore, we can accomodate
// TX_RING_SIZE-1 buffers.
if (e1000.txinuse == TX_RING_SIZE-1) {
cprintf("TX ring overflow\n");
return -1;
}
tail = erd(WMREG_TDT);
desc = &e1000.txd[tail];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
panic("oops");
desc->wtx_addr = v2p(buf);
desc->wtx_cmdlen = len | WTX_CMD_RS | WTX_CMD_EOP | WTX_CMD_IFCS;
memset(&desc->wtx_fields, 0, sizeof(&desc->wtx_fields));
ewr(WMREG_TDT, (tail+1) % TX_RING_SIZE);
e1000.txinuse++;
return 0;
}
static void
cleantx(void)
{
struct wiseman_txdesc *desc;
void *va;
while (e1000.txinuse) {
desc = &e1000.txd[e1000.txclean];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
break;
va = p2v(desc->wtx_addr);
netfree(va);
desc->wtx_fields.wtxu_status = 0;
e1000.txclean = (e1000.txclean+1) % TX_RING_SIZE;
desc = &e1000.txd[e1000.txclean];
e1000.txinuse--;
}
}
static void
allocrx(void)
{
struct wiseman_rxdesc *desc;
void *buf;
u32 i;
i = erd(WMREG_RDT);
desc = &e1000.rxd[i];
if (desc->wrx_status & WRX_ST_DD)
panic("allocrx");
buf = netalloc();
if (buf == NULL)
panic("Oops");
desc->wrx_addr = v2p(buf);
ewr(WMREG_RDT, (i+1) % RX_RING_SIZE);
}
static void
cleanrx(void)
{
struct wiseman_rxdesc *desc;
void *va;
u16 len;
u32 i;
i = e1000.rxclean;
desc = &e1000.rxd[i];
while (desc->wrx_status & WRX_ST_DD) {
va = p2v(desc->wrx_addr);
len = desc->wrx_len;
desc->wrx_status = 0;
allocrx();
netrx(va, len);
i = (i+1) % RX_RING_SIZE;
desc = &e1000.rxd[i];
}
e1000.rxclean = i;
}
void
e1000intr(void)
{
u32 icr = erd(WMREG_ICR);
while (icr & (ICR_TXDW|ICR_RXO|ICR_RXT0)) {
if (icr & ICR_TXDW)
cleantx();
if (icr & ICR_RXT0)
cleanrx();
if (icr & ICR_RXO)
panic("ICR_RXO");
icr = erd(WMREG_ICR);
}
}
static
void e1000reset(void)
{
u32 ctrl;
paddr tpa;
paddr rpa;
ctrl = erd(WMREG_CTRL);
// [E1000 13.4.1] Assert PHY_RESET then delay as much as 10 msecs
// before clearing PHY_RESET.
ewr(WMREG_CTRL, ctrl|CTRL_PHY_RESET);
microdelay(10000);
ewr(WMREG_CTRL, ctrl);
// [E1000 13.4.1] Delay 1 usec after reset
ewr(WMREG_CTRL, ctrl|CTRL_RST);
microdelay(1);
// [E1000 13.4.41] Transmit Interrupt Delay Value of 1 usec.
// A value of 0 is not allowed. Enabled on a per-TX decriptor basis.
ewr(WMREG_TIDV, 1);
// [E1000 13.4.44] Delay TX interrupts a max of 1 usec.
ewr(WMREG_TADV, 1);
for (int i = 0; i < TX_RING_SIZE; i++)
e1000.txd[i].wtx_fields.wtxu_status = WTX_ST_DD;
// [E1000 14.5] Transmit Initialization
tpa = v2p(e1000.txd);
ewr(WMREG_TDBAH, tpa >> 32);
ewr(WMREG_TDBAL, tpa & 0xffffffff);
ewr(WMREG_TDLEN, sizeof(e1000.txd));
ewr(WMREG_TDH, 0);
ewr(WMREG_TDT, 0);
ewr(WMREG_TCTL, TCTL_EN|TCTL_PSP|TCTL_CT(0x10)|TCTL_COLD(0x40));
ewr(WMREG_TIPG, TIPG_IPGT(10)|TIPG_IPGR1(8)|TIPG_IPGR2(6));
for (int i = 0; i < RX_RING_SIZE>>1; i++) {
void *buf = netalloc();
e1000.rxd[i].wrx_addr = v2p(buf);
}
rpa = v2p(e1000.rxd);
ewr(WMREG_RDBAH, rpa >> 32);
ewr(WMREG_RDBAL, rpa & 0xffffffff);
ewr(WMREG_RDLEN, sizeof(e1000.rxd));
ewr(WMREG_RDH, 0);
ewr(WMREG_RDT, RX_RING_SIZE>>1);
ewr(WMREG_RDTR, 0);
ewr(WMREG_RADV, 0);
ewr(WMREG_RCTL,
RCTL_EN | RCTL_RDMTS_1_2 | RCTL_DPF | RCTL_BAM | RCTL_2k);
ewr(WMREG_RDT, RX_RING_SIZE-1);
// [E1000 13.4.20]
ewr(WMREG_IMC, ~0);
ewr(WMREG_IMS, ICR_TXDW | ICR_RXO | ICR_RXT0);
}
//#define E1000_WRITE_FLUSH() erd(WMREG_STATUS)
int
e1000attach(struct pci_func *pcif) e1000attach(struct pci_func *pcif)
{ {
int r; int r;
...@@ -67,6 +251,12 @@ e1000attach(struct pci_func *pcif) ...@@ -67,6 +251,12 @@ e1000attach(struct pci_func *pcif)
e1000.membase = pcif->reg_base[0]; e1000.membase = pcif->reg_base[0];
e1000.iobase = pcif->reg_base[2]; e1000.iobase = pcif->reg_base[2];
e1000.pcidevid = pcif->dev_id; e1000.pcidevid = pcif->dev_id;
e1000irq = pcif->irq_line;
picenable(e1000irq);
ioapicenable(e1000irq, 0);
e1000reset();
// Get the MAC address // Get the MAC address
u16 myaddr[3]; u16 myaddr[3];
......
...@@ -65,6 +65,11 @@ void panic(const char*) __attribute__((noreturn)); ...@@ -65,6 +65,11 @@ void panic(const char*) __attribute__((noreturn));
void snprintf(char *buf, u32 n, char *fmt, ...); void snprintf(char *buf, u32 n, char *fmt, ...);
void consoleintr(int(*)(void)); void consoleintr(int(*)(void));
// e1000.c
extern int e1000irq;
void e1000intr(void);
int e1000tx(void *buf, u32 len);
// exec.c // exec.c
int exec(char*, char**); int exec(char*, char**);
...@@ -139,6 +144,11 @@ void lapicpc(char mask); ...@@ -139,6 +144,11 @@ void lapicpc(char mask);
extern int ncpu; extern int ncpu;
int mpbcpu(void); int mpbcpu(void);
// net.c
void netfree(void *va);
void* netalloc(void);
void netrx(void *va, u16 len);
// ns.c // ns.c
enum { enum {
nskey_int = 1, nskey_int = 1,
......
#include "types.h"
#include "kernel.h"
static u8 ping_packet[] = {
0x52, 0x55, 0x0a, 0x00, 0x02, 0x02, 0x52, 0x54, 0x00, 0x12,
0x34, 0x56, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0x00, 0x00,
0x40, 0x00, 0x40, 0x01, 0x22, 0x99, 0x0a, 0x00, 0x02, 0x0f,
0x0a, 0x00, 0x02, 0x02, 0x08, 0x00, 0x94, 0xa0, 0x03, 0x07,
0x00, 0x01, 0x71, 0xfc, 0xec, 0x4e, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x39, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
};
void
netfree(void *va)
{
kfree(va);
}
void *
netalloc(void)
{
return kalloc();
}
void
netrx(void *va, u16 len)
{
cprintf("netrx %lx len %x\n", va, len);
}
void
nettest(void)
{
void *ping;
u32 len;
ping = netalloc();
len = sizeof(ping_packet);
memmove(ping, ping_packet, len);
e1000tx(ping, len);
//e1000tx(ping_packet, sizeof(ping_packet));
}
...@@ -30,11 +30,12 @@ struct pci_driver pci_attach_class[] = { ...@@ -30,11 +30,12 @@ struct pci_driver pci_attach_class[] = {
}; };
// pci_attach_vendor matches the vendor ID and device ID of a PCI device // pci_attach_vendor matches the vendor ID and device ID of a PCI device
// http://www.intel.com/products/ethernet/resource.htm?wapkw=software%20manual%20pcie#s1=Gigabit%20Ethernet&s2=all&s3=Manual
struct pci_driver pci_attach_vendor[] = { struct pci_driver pci_attach_vendor[] = {
// [E1000 5.2] // [E1000 5.2]
// QEMU emulates an 82540EM, specifically. // QEMU emulates an 82540EM, specifically.
{ 0x8086, 0x100e, &e1000attach }, { 0x8086, 0x100e, &e1000attach },
// Both of ud0's e1000e // Both of ud0's e1000e (82573E, 82573L)
{ 0x8086, 0x108c, &e1000attach }, { 0x8086, 0x108c, &e1000attach },
{ 0x8086, 0x109A, &e1000attach }, { 0x8086, 0x109A, &e1000attach },
{ 0, 0, 0 }, { 0, 0, 0 },
......
...@@ -117,6 +117,13 @@ trap(struct trapframe *tf) ...@@ -117,6 +117,13 @@ trap(struct trapframe *tf)
sampconf(); sampconf();
break; break;
default: default:
if (tf->trapno == T_IRQ0+e1000irq) {
e1000intr();
lapiceoi();
piceoi();
break;
}
if(myproc() == 0 || (tf->cs&3) == 0){ if(myproc() == 0 || (tf->cs&3) == 0){
// In kernel, it must be our mistake. // In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d rip %lx (cr2=0x%lx)\n", cprintf("unexpected trap %d from cpu %d rip %lx (cr2=0x%lx)\n",
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论