提交 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 = \
main.o \
memide.o \
mp.o \
net.o \
ns.o \
pci.o \
picirq.o \
......@@ -142,7 +143,9 @@ $(O)/mscan.kern: $(O)/kernel
##
## 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) $(QEMUOPTS) -kernel $(O)/kernel
......
......@@ -4,22 +4,36 @@
#include "pci.h"
#include "e1000reg.h"
#define TX_RING_SIZE 64
#define RX_RING_SIZE 64
int e1000irq;
static struct {
u32 membase;
u32 iobase;
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;
static u32
e1000_io_read(u32 reg)
static inline u32
erd(u32 reg)
{
paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa);
return *ptr;
}
static void
e1000_io_write(u32 reg, u32 val)
static inline void
ewr(u32 reg, u32 val)
{
paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa);
......@@ -33,9 +47,9 @@ eeprom_eerd_read(u16 off)
int x;
// [E1000 5.3.1] Software EEPROM access
e1000_io_write(WMREG_EERD, (off<<EERD_ADDR_SHIFT) | EERD_START);
for (x = 0; x < 100; x++) {
reg = e1000_io_read(WMREG_EERD);
ewr(WMREG_EERD, (off<<EERD_ADDR_SHIFT) | EERD_START);
for (x = 0; x < 5; x++) {
reg = erd(WMREG_EERD);
if (reg & EERD_DONE)
return (reg&EERD_DATA_MASK) >> EERD_DATA_SHIFT;
microdelay(50000);
......@@ -58,6 +72,176 @@ eeprom_read(u16 *buf, int off, int count)
}
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)
{
int r;
......@@ -67,6 +251,12 @@ e1000attach(struct pci_func *pcif)
e1000.membase = pcif->reg_base[0];
e1000.iobase = pcif->reg_base[2];
e1000.pcidevid = pcif->dev_id;
e1000irq = pcif->irq_line;
picenable(e1000irq);
ioapicenable(e1000irq, 0);
e1000reset();
// Get the MAC address
u16 myaddr[3];
......
......@@ -65,6 +65,11 @@ void panic(const char*) __attribute__((noreturn));
void snprintf(char *buf, u32 n, char *fmt, ...);
void consoleintr(int(*)(void));
// e1000.c
extern int e1000irq;
void e1000intr(void);
int e1000tx(void *buf, u32 len);
// exec.c
int exec(char*, char**);
......@@ -139,6 +144,11 @@ void lapicpc(char mask);
extern int ncpu;
int mpbcpu(void);
// net.c
void netfree(void *va);
void* netalloc(void);
void netrx(void *va, u16 len);
// ns.c
enum {
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[] = {
};
// 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[] = {
// [E1000 5.2]
// QEMU emulates an 82540EM, specifically.
{ 0x8086, 0x100e, &e1000attach },
// Both of ud0's e1000e
// Both of ud0's e1000e (82573E, 82573L)
{ 0x8086, 0x108c, &e1000attach },
{ 0x8086, 0x109A, &e1000attach },
{ 0, 0, 0 },
......
......@@ -117,6 +117,13 @@ trap(struct trapframe *tf)
sampconf();
break;
default:
if (tf->trapno == T_IRQ0+e1000irq) {
e1000intr();
lapiceoi();
piceoi();
break;
}
if(myproc() == 0 || (tf->cs&3) == 0){
// In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d rip %lx (cr2=0x%lx)\n",
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论