diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2012-02-29 15:37:43 +0100 |
---|---|---|
committer | Jan Kiszka <jan.kiszka@siemens.com> | 2012-04-16 15:41:28 +0200 |
commit | ef45c9147f534531ef5d8a20315089d43ea4ddef (patch) | |
tree | ef65aa0c6947c47e3c08ef6f8d2e0991e0a9a262 /hw/pcnet.c | |
parent | 6655124ddd6442b19a4b43b27e7d5a3846c4e6a8 (diff) | |
download | qemu-ef45c9147f534531ef5d8a20315089d43ea4ddef.zip qemu-ef45c9147f534531ef5d8a20315089d43ea4ddef.tar.gz qemu-ef45c9147f534531ef5d8a20315089d43ea4ddef.tar.bz2 |
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 <jan.kiszka@siemens.com>
Diffstat (limited to 'hw/pcnet.c')
-rw-r--r-- | hw/pcnet.c | 11 |
1 files changed, 11 insertions, 0 deletions
@@ -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))) |