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

E1000 locking

上级 2ada02f9
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "amd64.h" #include "amd64.h"
#include "kernel.h" #include "kernel.h"
#include "pci.h" #include "pci.h"
#include "spinlock.h"
#include "e1000reg.h" #include "e1000reg.h"
#define TX_RING_SIZE 64 #define TX_RING_SIZE 64
...@@ -14,16 +15,18 @@ static struct { ...@@ -14,16 +15,18 @@ static struct {
u32 iobase; u32 iobase;
u16 pcidevid; u16 pcidevid;
u32 txclean; volatile u32 txclean;
u32 txinuse; volatile u32 txinuse;
u32 rxclean; volatile u32 rxclean;
u32 rxuse; volatile u32 rxuse;
u8 hwaddr[6]; u8 hwaddr[6];
struct wiseman_txdesc txd[TX_RING_SIZE] __attribute__((aligned (16))); struct wiseman_txdesc txd[TX_RING_SIZE] __attribute__((aligned (16)));
struct wiseman_rxdesc rxd[RX_RING_SIZE] __attribute__((aligned (16))); struct wiseman_rxdesc rxd[RX_RING_SIZE] __attribute__((aligned (16)));
struct spinlock lk;
} e1000; } e1000;
static inline u32 static inline u32
...@@ -79,24 +82,27 @@ e1000tx(void *buf, u32 len) ...@@ -79,24 +82,27 @@ e1000tx(void *buf, u32 len)
struct wiseman_txdesc *desc; struct wiseman_txdesc *desc;
u32 tail; u32 tail;
acquire(&e1000.lk);
// WMREG_TDT should only equal WMREG_TDH when we have // WMREG_TDT should only equal WMREG_TDH when we have
// nothing to transmit. Therefore, we can accomodate // nothing to transmit. Therefore, we can accomodate
// TX_RING_SIZE-1 buffers. // TX_RING_SIZE-1 buffers.
if (e1000.txinuse == TX_RING_SIZE-1) { if (e1000.txinuse == TX_RING_SIZE-1) {
cprintf("TX ring overflow\n"); cprintf("TX ring overflow\n");
release(&e1000.lk);
return -1; return -1;
} }
tail = erd(WMREG_TDT); tail = erd(WMREG_TDT);
desc = &e1000.txd[tail]; desc = &e1000.txd[tail];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD)) if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
panic("oops"); panic("e1000tx");
desc->wtx_addr = v2p(buf); desc->wtx_addr = v2p(buf);
desc->wtx_cmdlen = len | WTX_CMD_RS | WTX_CMD_EOP | WTX_CMD_IFCS; desc->wtx_cmdlen = len | WTX_CMD_RS | WTX_CMD_EOP | WTX_CMD_IFCS;
memset(&desc->wtx_fields, 0, sizeof(&desc->wtx_fields)); memset(&desc->wtx_fields, 0, sizeof(desc->wtx_fields));
ewr(WMREG_TDT, (tail+1) % TX_RING_SIZE); ewr(WMREG_TDT, (tail+1) % TX_RING_SIZE);
e1000.txinuse++; e1000.txinuse++;
release(&e1000.lk);
return 0; return 0;
} }
...@@ -107,6 +113,7 @@ cleantx(void) ...@@ -107,6 +113,7 @@ cleantx(void)
struct wiseman_txdesc *desc; struct wiseman_txdesc *desc;
void *va; void *va;
acquire(&e1000.lk);
while (e1000.txinuse) { while (e1000.txinuse) {
desc = &e1000.txd[e1000.txclean]; desc = &e1000.txd[e1000.txclean];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD)) if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
...@@ -114,12 +121,13 @@ cleantx(void) ...@@ -114,12 +121,13 @@ cleantx(void)
va = p2v(desc->wtx_addr); va = p2v(desc->wtx_addr);
netfree(va); netfree(va);
desc->wtx_fields.wtxu_status = 0; desc->wtx_fields.wtxu_status = WTX_ST_DD;
e1000.txclean = (e1000.txclean+1) % TX_RING_SIZE; e1000.txclean = (e1000.txclean+1) % TX_RING_SIZE;
desc = &e1000.txd[e1000.txclean]; desc = &e1000.txd[e1000.txclean];
e1000.txinuse--; e1000.txinuse--;
} }
release(&e1000.lk);
} }
static void static void
...@@ -147,23 +155,25 @@ cleanrx(void) ...@@ -147,23 +155,25 @@ cleanrx(void)
struct wiseman_rxdesc *desc; struct wiseman_rxdesc *desc;
void *va; void *va;
u16 len; u16 len;
u32 i;
i = e1000.rxclean;
desc = &e1000.rxd[i];
acquire(&e1000.lk);
desc = &e1000.rxd[e1000.rxclean];
while (desc->wrx_status & WRX_ST_DD) { while (desc->wrx_status & WRX_ST_DD) {
va = p2v(desc->wrx_addr); va = p2v(desc->wrx_addr);
len = desc->wrx_len; len = desc->wrx_len;
desc->wrx_status = 0; desc->wrx_status = 0;
allocrx(); allocrx();
e1000.rxclean = (e1000.rxclean+1) % RX_RING_SIZE;
release(&e1000.lk);
netrx(va, len); netrx(va, len);
acquire(&e1000.lk);
i = (i+1) % RX_RING_SIZE; desc = &e1000.rxd[e1000.rxclean];
desc = &e1000.rxd[i];
} }
e1000.rxclean = i; release(&e1000.lk);
} }
void void
...@@ -254,6 +264,7 @@ e1000attach(struct pci_func *pcif) ...@@ -254,6 +264,7 @@ e1000attach(struct pci_func *pcif)
pci_func_enable(pcif); pci_func_enable(pcif);
initlock(&e1000.lk, "e1000");
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;
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论