From 6655124ddd6442b19a4b43b27e7d5a3846c4e6a8 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 29 Feb 2012 15:33:48 +0100 Subject: pcnet: Clear ERR in CSR0 on stop pcnet_stop already clears any reason (BABL, CERR, MISS, MERR) why ERR (bit 15) should be set in CRS0. So we have to clear that bit as well. Signed-off-by: Jan Kiszka --- hw/pcnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'hw/pcnet.c') diff --git a/hw/pcnet.c b/hw/pcnet.c index c53f06ef3b..7413409331 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -884,7 +884,7 @@ static void pcnet_stop(PCNetState *s) #ifdef PCNET_DEBUG printf("pcnet_stop\n"); #endif - s->csr[0] &= ~0x7feb; + s->csr[0] &= ~0xffeb; s->csr[0] |= 0x0014; s->csr[4] &= ~0x02c2; s->csr[5] &= ~0x0011; -- cgit 1.4.1 From ef45c9147f534531ef5d8a20315089d43ea4ddef Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Wed, 29 Feb 2012 15:37:43 +0100 Subject: pcnet: Properly handle TX requests during Link Fail As long as we have no link and we aren't in internal loopback mode, no packet must be sent. Instead, LCAR needs to be set in any active TX descriptor and also CERR in CSR0. Signed-off-by: Jan Kiszka --- hw/pcnet.c | 11 +++++++++++ hw/pcnet.h | 1 + 2 files changed, 12 insertions(+) (limited to 'hw/pcnet.c') diff --git a/hw/pcnet.c b/hw/pcnet.c index 7413409331..d769b08b78 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -77,6 +77,7 @@ struct qemu_ether_header { #define CSR_DTX(S) !!(((S)->csr[15])&0x0002) #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) #define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008) +#define CSR_INTL(S) !!(((S)->csr[15])&0x0040) #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) #define CSR_PROM(S) !!(((S)->csr[15])&0x8000) @@ -1234,6 +1235,15 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) != 1) add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS); } + if (s->lnkst == 0 && + (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) { + SET_FIELD(&tmd.misc, TMDM, LCAR, 1); + SET_FIELD(&tmd.status, TMDS, ERR, 1); + SET_FIELD(&tmd.status, TMDS, OWN, 0); + s->csr[0] |= 0xa000; /* ERR | CERR */ + s->xmit_pos = -1; + goto txdone; + } if (!GET_FIELD(tmd.status, TMDS, ENP)) { int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), @@ -1262,6 +1272,7 @@ static void pcnet_transmit(PCNetState *s) s->xmit_pos = -1; } + txdone: SET_FIELD(&tmd.status, TMDS, OWN, 0); TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT))) diff --git a/hw/pcnet.h b/hw/pcnet.h index edc81c90ac..803a2cc1ec 100644 --- a/hw/pcnet.h +++ b/hw/pcnet.h @@ -20,6 +20,7 @@ #define BCR_SWS 20 #define BCR_PLAT 22 +#define BCR_TMAULOOP(S) !!((S)->bcr[BCR_MC ] & 0x4000) #define BCR_APROMWE(S) !!((S)->bcr[BCR_MC ] & 0x0100) #define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) #define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) -- cgit 1.4.1