Files
2013-09-26 17:14:40 +02:00

758 lines
25 KiB
Plaintext

$NetBSD: patch-cq,v 1.1.1.1 2007/06/14 19:42:12 bouyer Exp $
This is a backport of bugfixes and changes in xen-unstable to make pcnet
usable. It gives better performances than the ne2000 or realtek emulations.
--- ioemu/hw/pcnet.c.orig 2007-06-13 19:06:54.000000000 +0200
+++ ioemu/hw/pcnet.c 2007-06-13 19:54:43.000000000 +0200
@@ -41,25 +41,6 @@
#define PCNET_IOPORT_SIZE 0x20
#define PCNET_PNPMMIO_SIZE 0x20
-
-typedef struct PCNetState_st PCNetState;
-
-struct PCNetState_st {
- PCIDevice dev;
- VLANClientState *vc;
- NICInfo *nd;
- QEMUTimer *poll_timer;
- int mmio_io_addr, rap, isr, lnkst;
- target_phys_addr_t rdra, tdra;
- uint8_t prom[16];
- uint16_t csr[128];
- uint16_t bcr[32];
- uint64_t timer;
- int xmit_pos, recv_pos;
- uint8_t buffer[4096];
- int tx_busy;
-};
-
/* XXX: using bitfields for target memory structures is almost surely
not portable, so it should be suppressed ASAP */
#ifdef __GNUC__
@@ -251,6 +232,28 @@
(R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
(R)->rmd2.zeros)
+typedef struct PCNetState_st PCNetState;
+
+struct PCNetState_st {
+ PCIDevice dev;
+ VLANClientState *vc;
+ NICInfo *nd;
+ QEMUTimer *poll_timer;
+ int mmio_io_addr, rap, isr, lnkst;
+ target_phys_addr_t rdra, tdra;
+ uint8_t prom[16];
+ uint16_t csr[128];
+ uint16_t bcr[32];
+ uint64_t timer;
+ int recv_pos;
+ uint8_t tx_buffer[2048];
+ uint8_t rx_buffer[2048];
+ struct pcnet_TMD tmd;
+ struct pcnet_RMD crmd;
+ struct pcnet_RMD nrmd;
+ struct pcnet_RMD nnrmd;
+};
+
static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
{
if (!BCR_SWSTYLE(s)) {
@@ -269,18 +272,17 @@
if (BCR_SWSTYLE(s) != 3)
cpu_physical_memory_read(addr, (void *)tmd, 16);
else {
- uint32_t xda[4];
- cpu_physical_memory_read(addr,
- (void *)&xda[0], sizeof(xda));
- ((uint32_t *)tmd)[0] = xda[2];
- ((uint32_t *)tmd)[1] = xda[1];
- ((uint32_t *)tmd)[2] = xda[0];
- ((uint32_t *)tmd)[3] = xda[3];
+ uint32_t xda[2];
+ cpu_physical_memory_read(addr+4, (void *)&xda[0], sizeof(xda));
+ ((uint32_t *)tmd)[0] = xda[1];
+ ((uint32_t *)tmd)[1] = xda[0];
+ ((uint32_t *)tmd)[2] = 0;
}
}
static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
{
+ tmd->tmd1.own = 0;
if (!BCR_SWSTYLE(s)) {
uint16_t xda[4];
xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
@@ -295,14 +297,12 @@
if (BCR_SWSTYLE(s) != 3)
cpu_physical_memory_write(addr, (void *)tmd, 16);
else {
- uint32_t xda[4];
+ uint32_t xda[2];
xda[0] = ((uint32_t *)tmd)[2];
xda[1] = ((uint32_t *)tmd)[1];
- xda[2] = ((uint32_t *)tmd)[0];
- xda[3] = ((uint32_t *)tmd)[3];
- cpu_physical_memory_write(addr,
- (void *)&xda[0], sizeof(xda));
+ cpu_physical_memory_write(addr, (void *)&xda[0], sizeof(xda));
}
+ cpu_physical_memory_set_dirty(addr+15);
}
}
@@ -320,21 +320,22 @@
((uint32_t *)rmd)[3] = 0;
}
else
- if (BCR_SWSTYLE(s) != 3)
+ if (BCR_SWSTYLE(s) != 3) {
+ ((uint32_t *)rmd)[2] = 0;
cpu_physical_memory_read(addr, (void *)rmd, 16);
- else {
- uint32_t rda[4];
- cpu_physical_memory_read(addr,
- (void *)&rda[0], sizeof(rda));
- ((uint32_t *)rmd)[0] = rda[2];
- ((uint32_t *)rmd)[1] = rda[1];
- ((uint32_t *)rmd)[2] = rda[0];
- ((uint32_t *)rmd)[3] = rda[3];
+ } else {
+ uint32_t rda[2];
+ cpu_physical_memory_read(addr+4, (void *)&rda[0], sizeof(rda));
+ ((uint32_t *)rmd)[0] = rda[1];
+ ((uint32_t *)rmd)[1] = rda[0];
+ ((uint32_t *)rmd)[2] = 0;
}
}
static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
{
+ rmd->rmd1.own = 0;
+ cpu_physical_memory_set_dirty(addr);
if (!BCR_SWSTYLE(s)) {
uint16_t rda[4]; \
rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
@@ -349,13 +350,10 @@
if (BCR_SWSTYLE(s) != 3)
cpu_physical_memory_write(addr, (void *)rmd, 16);
else {
- uint32_t rda[4];
+ uint32_t rda[2];
rda[0] = ((uint32_t *)rmd)[2];
rda[1] = ((uint32_t *)rmd)[1];
- rda[2] = ((uint32_t *)rmd)[0];
- rda[3] = ((uint32_t *)rmd)[3];
- cpu_physical_memory_write(addr,
- (void *)&rda[0], sizeof(rda));
+ cpu_physical_memory_write(addr, (void *)&rda[0], sizeof(rda));
}
}
}
@@ -369,81 +367,16 @@
#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
-#if 1
-
-#define CHECK_RMD(ADDR,RES) do { \
- struct pcnet_RMD rmd; \
- RMDLOAD(&rmd,(ADDR)); \
- (RES) |= (rmd.rmd1.ones != 15) \
- || (rmd.rmd2.zeros != 0); \
+#define CHECK_RMD(RMD,ADDR,RES) do { \
+ RMDLOAD((RMD),(ADDR)); \
+ (RES) |= ((RMD)->rmd1.ones != 15); \
} while (0)
#define CHECK_TMD(ADDR,RES) do { \
- struct pcnet_TMD tmd; \
- TMDLOAD(&tmd,(ADDR)); \
- (RES) |= (tmd.tmd1.ones != 15); \
+ TMDLOAD(&(s->tmd),(ADDR)); \
+ (RES) |= (s->tmd.tmd1.ones != 15); \
} while (0)
-#else
-
-#define CHECK_RMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[2] & 0xf000)!=0xf000; \
- (RES) |= (rda[3] & 0xf000)!=0x0000; \
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- do { \
- uint32_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
- } while (0); \
- break; \
- case 0x03: \
- do { \
- uint32_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t xda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&xda[0], sizeof(xda)); \
- (RES) |= (xda[2] & 0xf000)!=0xf000;\
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- case 0x03: \
- do { \
- uint32_t xda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&xda[0], sizeof(xda)); \
- (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#endif
-
#define PRINT_PKTHDR(BUF) do { \
struct qemu_ether_header *hdr = (void *)(BUF); \
printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
@@ -662,8 +595,6 @@
s->csr[114] = 0x0000;
s->csr[122] = 0x0000;
s->csr[124] = 0x0000;
-
- s->tx_busy = 0;
}
static void pcnet_update_irq(PCNetState *s)
@@ -737,6 +668,9 @@
s->csr[15] = le16_to_cpu(initblk.mode); \
CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
+ s->crmd.rmd1.own = 0; \
+ s->nrmd.rmd1.own = 0; \
+ s->nnrmd.rmd1.own = 0; \
s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
@@ -791,6 +725,10 @@
if (!CSR_DRX(s))
s->csr[0] |= 0x0020; /* set RXON */
+ /* flush any cached receive descriptors */
+ s->crmd.rmd1.own = 0;
+ s->nrmd.rmd1.own = 0;
+ s->nnrmd.rmd1.own = 0;
s->csr[0] &= ~0x0004; /* clear STOP bit */
s->csr[0] |= 0x0002;
@@ -813,29 +751,21 @@
s->csr[28] = s->csr[29] = 0;
if (s->rdra) {
int bad = 0;
-#if 1
target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
-#else
- target_phys_addr_t crda = s->rdra +
- (CSR_RCVRL(s) - CSR_RCVRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
- target_phys_addr_t nrda = s->rdra +
- (CSR_RCVRL(s) - nrdc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
- target_phys_addr_t nnrd = s->rdra +
- (CSR_RCVRL(s) - nnrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
-#endif
- CHECK_RMD(PHYSADDR(s,crda), bad);
+ if (!s->crmd.rmd1.own) {
+ CHECK_RMD(&(s->crmd),PHYSADDR(s,crda), bad);
+ }
if (!bad) {
- CHECK_RMD(PHYSADDR(s,nrda), bad);
+ if (s->crmd.rmd1.own && !s->nrmd.rmd1.own) {
+ CHECK_RMD(&(s->nrmd),PHYSADDR(s,nrda), bad);
+ }
if (bad || (nrda == crda)) nrda = 0;
- CHECK_RMD(PHYSADDR(s,nnrd), bad);
+ if (s->crmd.rmd1.own && s->nrmd.rmd1.own && !s->nnrmd.rmd1.own) {
+ CHECK_RMD(&(s->nnrmd),PHYSADDR(s,nnrd), bad);
+ }
if (bad || (nnrd == crda)) nnrd = 0;
s->csr[28] = crda & 0xffff;
@@ -856,14 +786,12 @@
}
if (CSR_CRDA(s)) {
- struct pcnet_RMD rmd;
- RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
- CSR_CRBC(s) = rmd.rmd1.bcnt;
- CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+ CSR_CRBC(s) = s->crmd.rmd1.bcnt;
+ CSR_CRST(s) = ((uint32_t *)&(s->crmd))[1] >> 16;
#ifdef PCNET_DEBUG_RMD_X
printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
- ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
+ ((uint32_t *)&(s->crmd))[1], ((uint32_t *)&(s->crmd))[2]);
PRINT_RMD(&rmd);
#endif
} else {
@@ -871,10 +799,8 @@
}
if (CSR_NRDA(s)) {
- struct pcnet_RMD rmd;
- RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
- CSR_NRBC(s) = rmd.rmd1.bcnt;
- CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+ CSR_NRBC(s) = s->nrmd.rmd1.bcnt;
+ CSR_NRST(s) = ((uint32_t *)&(s->nrmd))[1] >> 16;
} else {
CSR_NRBC(s) = CSR_NRST(s) = 0;
}
@@ -889,6 +815,7 @@
(CSR_XMTRL(s) - CSR_XMTRC(s)) *
(BCR_SWSTYLE(s) ? 16 : 8 );
int bad = 0;
+ s->csr[0] &= ~0x0008; /* clear TDMD */
CHECK_TMD(PHYSADDR(s, cxda),bad);
if (!bad) {
if (CSR_CXDA(s) != cxda) {
@@ -907,12 +834,8 @@
}
if (CSR_CXDA(s)) {
- struct pcnet_TMD tmd;
-
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
- CSR_CXBC(s) = tmd.tmd1.bcnt;
- CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
+ CSR_CXBC(s) = s->tmd.tmd1.bcnt;
+ CSR_CXST(s) = ((uint32_t *)&(s->tmd))[1] >> 16;
} else {
CSR_CXBC(s) = CSR_CXST(s) = 0;
}
@@ -925,11 +848,12 @@
PCNetState *s = opaque;
if (CSR_STOP(s) || CSR_SPND(s))
return 0;
-
- if (s->recv_pos > 0)
- return 0;
- return sizeof(s->buffer)-16;
+ if (!(CSR_CRST(s) & 0x8000)) {
+ return 0;
+ }
+
+ return sizeof(s->rx_buffer)-16;
}
#define MIN_BUF_SIZE 60
@@ -938,7 +862,7 @@
{
PCNetState *s = opaque;
int is_padr = 0, is_bcast = 0, is_ladr = 0;
- uint8_t buf1[60];
+ int pad;
if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
return;
@@ -948,12 +872,10 @@
#endif
/* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
+ if (size < MIN_BUF_SIZE)
+ pad = MIN_BUF_SIZE - size + 4;
+ else
+ pad = 4;
if (CSR_PROM(s)
|| (is_padr=padr_match(s, buf, size))
@@ -962,125 +884,75 @@
pcnet_rdte_poll(s);
- if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
- struct pcnet_RMD rmd;
- int rcvrc = CSR_RCVRC(s)-1,i;
- target_phys_addr_t nrda;
- for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
- if (rcvrc <= 1)
- rcvrc = CSR_RCVRL(s);
- nrda = s->rdra +
- (CSR_RCVRL(s) - rcvrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
+ if (size > 2000) {
#ifdef PCNET_DEBUG_RMD
- printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
- rcvrc, CSR_RCVRC(s));
+ printf("pcnet - oversize packet discarded.\n");
#endif
- CSR_RCVRC(s) = rcvrc;
- pcnet_rdte_poll(s);
- break;
- }
- }
- }
-
- if (!(CSR_CRST(s) & 0x8000)) {
+ } else if (!(CSR_CRST(s) & 0x8000)) {
#ifdef PCNET_DEBUG_RMD
printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
#endif
s->csr[0] |= 0x1000; /* Set MISS flag */
CSR_MISSC(s)++;
} else {
- uint8_t *src = &s->buffer[8];
+ uint8_t *src = &s->rx_buffer[8];
target_phys_addr_t crda = CSR_CRDA(s);
- struct pcnet_RMD rmd;
+ target_phys_addr_t nrda = CSR_NRDA(s);
+ target_phys_addr_t nnrda = CSR_NNRD(s);
int pktcount = 0;
+ int packet_size = size + pad;
memcpy(src, buf, size);
-#if 1
- /* no need to compute the CRC */
- src[size] = 0;
- src[size + 1] = 0;
- src[size + 2] = 0;
- src[size + 3] = 0;
- size += 4;
-#else
- /* XXX: avoid CRC generation */
- if (!CSR_ASTRP_RCV(s)) {
- uint32_t fcs = ~0;
- uint8_t *p = src;
-
- while (size < 46) {
- src[size++] = 0;
- }
-
- while (p != &src[size]) {
- CRC(fcs, *p++);
- }
- ((uint32_t *)&src[size])[0] = htonl(fcs);
- size += 4; /* FCS at end of packet */
- } else size += 4;
-#endif
+ memset(src + size, 0, pad);
+ size += pad;
#ifdef PCNET_DEBUG_MATCH
PRINT_PKTHDR(buf);
#endif
- RMDLOAD(&rmd, PHYSADDR(s,crda));
- /*if (!CSR_LAPPEN(s))*/
- rmd.rmd1.stp = 1;
-
-#define PCNET_RECV_STORE() do { \
- int count = MIN(4096 - rmd.rmd1.bcnt,size); \
- target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
- cpu_physical_memory_write(rbadr, src, count); \
- src += count; size -= count; \
- rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
- RMDSTORE(&rmd, PHYSADDR(s,crda)); \
- pktcount++; \
-} while (0)
-
- PCNET_RECV_STORE();
- if ((size > 0) && CSR_NRDA(s)) {
- target_phys_addr_t nrda = CSR_NRDA(s);
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
+ s->crmd.rmd1.stp = 1;
+ do {
+ int count = MIN(4096 - s->crmd.rmd1.bcnt,size);
+ target_phys_addr_t rbadr = PHYSADDR(s, s->crmd.rmd0.rbadr);
+ cpu_physical_memory_write(rbadr, src, count);
+ cpu_physical_memory_set_dirty(rbadr);
+ cpu_physical_memory_set_dirty(rbadr+count);
+ src += count; size -= count;
+ if (size > 0 && s->nrmd.rmd1.own) {
+ RMDSTORE(&(s->crmd), PHYSADDR(s,crda));
crda = nrda;
- PCNET_RECV_STORE();
- if ((size > 0) && (nrda=CSR_NNRD(s))) {
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
- crda = nrda;
- PCNET_RECV_STORE();
- }
- }
- }
- }
-
-#undef PCNET_RECV_STORE
+ nrda = nnrda;
+ s->crmd = s->nrmd;
+ s->nrmd = s->nnrmd;
+ s->nnrmd.rmd1.own = 0;
+ }
+ pktcount++;
+ } while (size > 0 && s->crmd.rmd1.own);
- RMDLOAD(&rmd, PHYSADDR(s,crda));
if (size == 0) {
- rmd.rmd1.enp = 1;
- rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
- rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
- rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
+ s->crmd.rmd1.enp = 1;
+ s->crmd.rmd2.mcnt = packet_size;
+ s->crmd.rmd1.pam = !CSR_PROM(s) && is_padr;
+ s->crmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
+ s->crmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
} else {
- rmd.rmd1.oflo = 1;
- rmd.rmd1.buff = 1;
- rmd.rmd1.err = 1;
+ s->crmd.rmd1.oflo = 1;
+ s->crmd.rmd1.buff = 1;
+ s->crmd.rmd1.err = 1;
}
- RMDSTORE(&rmd, PHYSADDR(s,crda));
+ RMDSTORE(&(s->crmd), PHYSADDR(s,crda));
s->csr[0] |= 0x0400;
+ s->crmd = s->nrmd;
+ s->nrmd = s->nnrmd;
+ s->nnrmd.rmd1.own = 0;
#ifdef PCNET_DEBUG
printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
#endif
#ifdef PCNET_DEBUG_RMD
- PRINT_RMD(&rmd);
+ PRINT_RMD(&s->crmd);
#endif
while (pktcount--) {
@@ -1101,81 +973,86 @@
static void pcnet_transmit(PCNetState *s)
{
- target_phys_addr_t xmit_cxda = 0;
+ target_phys_addr_t start_addr = 0;
+ struct pcnet_TMD start_tmd;
int count = CSR_XMTRL(s)-1;
- s->xmit_pos = -1;
+ int xmit_pos = 0;
+ int len;
if (!CSR_TXON(s)) {
s->csr[0] &= ~0x0008;
return;
}
- s->tx_busy = 1;
-
- txagain:
- if (pcnet_tdte_poll(s)) {
- struct pcnet_TMD tmd;
-
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+ while (pcnet_tdte_poll(s)) {
#ifdef PCNET_DEBUG_TMD
printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
- PRINT_TMD(&tmd);
+ PRINT_TMD(&(s->tmd));
#endif
- if (tmd.tmd1.stp) {
- s->xmit_pos = 0;
- if (!tmd.tmd1.enp) {
- cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer, 4096 - tmd.tmd1.bcnt);
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
- }
- xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
- }
- if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
- cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
-#ifdef PCNET_DEBUG
- printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif
- if (CSR_LOOP(s))
- pcnet_receive(s, s->buffer, s->xmit_pos);
- else
- qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
-
- s->csr[0] &= ~0x0008; /* clear TDMD */
- s->csr[4] |= 0x0004; /* set TXSTRT */
- s->xmit_pos = -1;
- }
+ len = 4096 - s->tmd.tmd1.bcnt;
+ if (CSR_XMTRC(s) <= 1)
+ CSR_XMTRC(s) = CSR_XMTRL(s);
+ else
+ CSR_XMTRC(s)--;
+ /* handle start followed by start */
+ if (s->tmd.tmd1.stp && start_addr) {
+ TMDSTORE(&start_tmd, start_addr);
+ start_addr = 0;
+ xmit_pos = 0;
+ }
+ if ((xmit_pos + len) < sizeof(s->tx_buffer)) {
+ cpu_physical_memory_read(PHYSADDR(s, s->tmd.tmd0.tbadr),
+ s->tx_buffer + xmit_pos, len);
+ xmit_pos += len;
+ } else {
+ s->tmd.tmd2.buff = s->tmd.tmd2.uflo = s->tmd.tmd1.err = 1;
+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
+ if (start_addr == PHYSADDR(s,CSR_CXDA(s)))
+ start_addr = 0; /* don't clear own bit twice */
+ continue;
+ }
+ if (s->tmd.tmd1.stp) {
+ if (s->tmd.tmd1.enp) {
+ if (CSR_LOOP(s))
+ pcnet_receive(s, s->tx_buffer, xmit_pos);
+ else
+ qemu_send_packet(s->vc, s->tx_buffer, xmit_pos);
+
+ s->csr[4] |= 0x0008; /* set TXSTRT */
+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
+ xmit_pos = 0;
+ count--;
+ } else {
+ start_tmd = s->tmd;
+ start_addr = PHYSADDR(s,CSR_CXDA(s));
+ }
+ } else if (s->tmd.tmd1.enp) {
+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
+ if (start_addr) {
+ TMDSTORE(&start_tmd, start_addr);
+ }
+ start_addr = 0;
+ xmit_pos = 0;
+ count--;
+ } else {
+ TMDSTORE(&(s->tmd), PHYSADDR(s,CSR_CXDA(s)));
+ }
- tmd.tmd1.own = 0;
- TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
- if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
+ if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && s->tmd.tmd1.ltint))
s->csr[0] |= 0x0200; /* set TINT */
- if (CSR_XMTRC(s)<=1)
- CSR_XMTRC(s) = CSR_XMTRL(s);
- else
- CSR_XMTRC(s)--;
- if (count--)
- goto txagain;
-
- } else
- if (s->xmit_pos >= 0) {
- struct pcnet_TMD tmd;
- TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
- tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
- tmd.tmd1.own = 0;
- TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
- s->csr[0] |= 0x0200; /* set TINT */
- if (!CSR_DXSUFLO(s)) {
- s->csr[0] &= ~0x0010;
- } else
- if (count--)
- goto txagain;
+ if (count <= 0)
+ break;
+ }
+ if (start_addr) {
+ start_tmd.tmd2.buff = start_tmd.tmd2.uflo = start_tmd.tmd1.err = 1;
+ TMDSTORE(&start_tmd, PHYSADDR(s,start_addr));
+ s->csr[0] |= 0x0200; /* set TINT */
+ if (!CSR_DXSUFLO(s)) {
+ s->csr[0] &= ~0x0010;
+ }
}
-
- s->tx_busy = 0;
}
static void pcnet_poll(PCNetState *s)
@@ -1186,13 +1063,7 @@
if (CSR_TDMD(s) ||
(CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
- {
- /* prevent recursion */
- if (s->tx_busy)
- return;
-
pcnet_transmit(s);
- }
}
static void pcnet_poll_timer(void *opaque)
@@ -1744,10 +1615,9 @@
for (i = 0; i < 32; i++)
qemu_put_be16s(f, &s->bcr[i]);
qemu_put_be64s(f, &s->timer);
- qemu_put_be32s(f, &s->xmit_pos);
qemu_put_be32s(f, &s->recv_pos);
- qemu_put_buffer(f, s->buffer, 4096);
- qemu_put_be32s(f, &s->tx_busy);
+ qemu_put_buffer(f, s->tx_buffer, 2048);
+ qemu_put_buffer(f, s->rx_buffer, 2048);
qemu_put_timer(f, s->poll_timer);
}
@@ -1770,10 +1640,9 @@
for (i = 0; i < 32; i++)
qemu_get_be16s(f, &s->bcr[i]);
qemu_get_be64s(f, &s->timer);
- qemu_get_be32s(f, &s->xmit_pos);
qemu_get_be32s(f, &s->recv_pos);
- qemu_get_buffer(f, s->buffer, 4096);
- qemu_get_be32s(f, &s->tx_busy);
+ qemu_get_buffer(f, s->tx_buffer, 2048);
+ qemu_get_buffer(f, s->rx_buffer, 2048);
qemu_get_timer(f, s->poll_timer);
return 0;