ia64/xen-unstable

view tools/ioemu/hw/pcnet.c @ 6608:b715a9f4dba0

Qemu-dm dumps core with the pcnet device. This patches fixes it.

When pcnet_receive calls pcnet_poll, which polls the receive and the send
rings. Whenever there is an element in the send ring that is owned by
the Lance chip it will call pcnet_transmit and send it. When the element
is the endp(acket), pcnet_transmit will copy it out, send the packet
(qemu_send_packet) and then clear the owner bit. Somewherer along the
qemu_send_packet execution path, pcnet_recieve is called again, which
calls pcnet_poll and starts this whole process again. This very rapidly
leads to a stack overflow and crashes qemu.

The fix is simple, stop the recursion. Once the packet is copied into
qemu datatstructure (before qemu_send_packet is called!), the owner bit
on the ring element should be cleared.

Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Sep 02 17:52:37 2005 +0000 (2005-09-02)
parents dd668f7527cb
children f27205ea60ef 29808fef9148
line source
1 /*
2 * QEMU AMD PC-Net II (Am79C970A) emulation
3 *
4 * Copyright (c) 2004 Antony T Curtis
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
25 /* This software was written to be compatible with the specification:
26 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
27 * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
28 */
30 #include "vl.h"
31 #include <sys/times.h>
32 #include <arpa/inet.h>
33 #include <net/ethernet.h>
35 //#define PCNET_DEBUG
36 //#define PCNET_DEBUG_IO
37 //#define PCNET_DEBUG_BCR
38 //#define PCNET_DEBUG_CSR
39 //#define PCNET_DEBUG_RMD
40 //#define PCNET_DEBUG_TMD
41 //#define PCNET_DEBUG_MATCH
44 #define PCNET_IOPORT_SIZE 0x20
45 #define PCNET_PNPMMIO_SIZE 0x20
48 typedef struct PCNetState_st PCNetState;
50 struct PCNetState_st {
51 PCIDevice dev;
52 NetDriverState *nd;
53 QEMUTimer *poll_timer;
54 int mmio_io_addr, rap, isr, lnkst;
55 target_phys_addr_t rdra, tdra;
56 uint8_t prom[16];
57 uint16_t csr[128];
58 uint16_t bcr[32];
59 uint64_t timer;
60 int xmit_pos, recv_pos;
61 uint8_t buffer[4096];
62 };
64 #include "pcnet.h"
66 static void pcnet_poll(PCNetState *s);
67 static void pcnet_poll_timer(void *opaque);
69 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
70 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
71 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
72 static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
74 static void pcnet_s_reset(PCNetState *s)
75 {
76 #ifdef PCNET_DEBUG
77 printf("pcnet_s_reset\n");
78 #endif
80 s->lnkst = 0x40;
81 s->rdra = 0;
82 s->tdra = 0;
83 s->rap = 0;
85 s->bcr[BCR_BSBC] &= ~0x0080;
87 s->csr[0] = 0x0004;
88 s->csr[3] = 0x0000;
89 s->csr[4] = 0x0115;
90 s->csr[5] = 0x0000;
91 s->csr[6] = 0x0000;
92 s->csr[8] = 0;
93 s->csr[9] = 0;
94 s->csr[10] = 0;
95 s->csr[11] = 0;
96 s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
97 s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
98 s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
99 s->csr[15] &= 0x21c4;
100 s->csr[72] = 1;
101 s->csr[74] = 1;
102 s->csr[76] = 1;
103 s->csr[78] = 1;
104 s->csr[80] = 0x1410;
105 s->csr[88] = 0x1003;
106 s->csr[89] = 0x0262;
107 s->csr[94] = 0x0000;
108 s->csr[100] = 0x0200;
109 s->csr[103] = 0x0105;
110 s->csr[103] = 0x0105;
111 s->csr[112] = 0x0000;
112 s->csr[114] = 0x0000;
113 s->csr[122] = 0x0000;
114 s->csr[124] = 0x0000;
115 }
117 static void pcnet_update_irq(PCNetState *s)
118 {
119 int isr = 0;
120 s->csr[0] &= ~0x0080;
122 #if 1
123 if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
124 (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
125 (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
126 #else
127 if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
128 (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
129 (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
130 (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
131 (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
132 (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
133 (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
134 (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
135 (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
136 (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
137 (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
138 (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
139 #endif
140 {
142 isr = CSR_INEA(s);
143 s->csr[0] |= 0x0080;
144 }
146 if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
147 s->csr[4] &= ~0x0080;
148 s->csr[4] |= 0x0040;
149 s->csr[0] |= 0x0080;
150 isr = 1;
151 #ifdef PCNET_DEBUG
152 printf("pcnet user int\n");
153 #endif
154 }
156 #if 1
157 if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
158 #else
159 if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
160 (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
161 #endif
162 {
163 isr = 1;
164 s->csr[0] |= 0x0080;
165 }
167 if (isr != s->isr) {
168 #ifdef PCNET_DEBUG
169 printf("pcnet: INTA=%d\n", isr);
170 #endif
171 }
172 pci_set_irq(&s->dev, 0, isr);
173 s->isr = isr;
174 }
176 static void pcnet_init(PCNetState *s)
177 {
178 #ifdef PCNET_DEBUG
179 printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
180 #endif
182 #define PCNET_INIT() do { \
183 cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \
184 (uint8_t *)&initblk, sizeof(initblk)); \
185 s->csr[15] = le16_to_cpu(initblk.mode); \
186 CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
187 CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
188 s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
189 s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
190 s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
191 s->csr[10] = le16_to_cpu(initblk.ladrf3); \
192 s->csr[11] = le16_to_cpu(initblk.ladrf4); \
193 s->csr[12] = le16_to_cpu(initblk.padr1); \
194 s->csr[13] = le16_to_cpu(initblk.padr2); \
195 s->csr[14] = le16_to_cpu(initblk.padr3); \
196 s->rdra = PHYSADDR(s,initblk.rdra); \
197 s->tdra = PHYSADDR(s,initblk.tdra); \
198 } while (0)
200 if (BCR_SSIZE32(s)) {
201 struct pcnet_initblk32 initblk;
202 PCNET_INIT();
203 #ifdef PCNET_DEBUG
204 printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
205 initblk.rlen, initblk.tlen);
206 #endif
207 } else {
208 struct pcnet_initblk16 initblk;
209 PCNET_INIT();
210 #ifdef PCNET_DEBUG
211 printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
212 initblk.rlen, initblk.tlen);
213 #endif
214 }
216 #undef PCNET_INIT
218 CSR_RCVRC(s) = CSR_RCVRL(s);
219 CSR_XMTRC(s) = CSR_XMTRL(s);
221 #ifdef PCNET_DEBUG
222 printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
223 BCR_SSIZE32(s),
224 s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
225 #endif
227 s->csr[0] |= 0x0101;
228 s->csr[0] &= ~0x0004; /* clear STOP bit */
229 }
231 static void pcnet_start(PCNetState *s)
232 {
233 #ifdef PCNET_DEBUG
234 printf("pcnet_start\n");
235 #endif
237 if (!CSR_DTX(s))
238 s->csr[0] |= 0x0010; /* set TXON */
240 if (!CSR_DRX(s))
241 s->csr[0] |= 0x0020; /* set RXON */
243 s->csr[0] &= ~0x0004; /* clear STOP bit */
244 s->csr[0] |= 0x0002;
245 }
247 static void pcnet_stop(PCNetState *s)
248 {
249 #ifdef PCNET_DEBUG
250 printf("pcnet_stop\n");
251 #endif
252 s->csr[0] &= ~0x7feb;
253 s->csr[0] |= 0x0014;
254 s->csr[4] &= ~0x02c2;
255 s->csr[5] &= ~0x0011;
256 pcnet_poll_timer(s);
257 }
259 static void pcnet_rdte_poll(PCNetState *s)
260 {
261 s->csr[28] = s->csr[29] = 0;
262 if (s->rdra) {
263 int bad = 0;
264 #if 1
265 target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
266 target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
267 target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
268 #else
269 target_phys_addr_t crda = s->rdra +
270 (CSR_RCVRL(s) - CSR_RCVRC(s)) *
271 (BCR_SWSTYLE(s) ? 16 : 8 );
272 int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
273 target_phys_addr_t nrda = s->rdra +
274 (CSR_RCVRL(s) - nrdc) *
275 (BCR_SWSTYLE(s) ? 16 : 8 );
276 int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
277 target_phys_addr_t nnrd = s->rdra +
278 (CSR_RCVRL(s) - nnrc) *
279 (BCR_SWSTYLE(s) ? 16 : 8 );
280 #endif
282 CHECK_RMD(PHYSADDR(s,crda), bad);
283 if (!bad) {
284 CHECK_RMD(PHYSADDR(s,nrda), bad);
285 if (bad || (nrda == crda)) nrda = 0;
286 CHECK_RMD(PHYSADDR(s,nnrd), bad);
287 if (bad || (nnrd == crda)) nnrd = 0;
289 s->csr[28] = crda & 0xffff;
290 s->csr[29] = crda >> 16;
291 s->csr[26] = nrda & 0xffff;
292 s->csr[27] = nrda >> 16;
293 s->csr[36] = nnrd & 0xffff;
294 s->csr[37] = nnrd >> 16;
295 #ifdef PCNET_DEBUG
296 if (bad) {
297 printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n",
298 PHYSADDR(s,crda));
299 }
300 } else {
301 printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda));
302 #endif
303 }
304 }
306 if (CSR_CRDA(s)) {
307 struct pcnet_RMD rmd;
308 RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
309 CSR_CRBC(s) = rmd.rmd1.bcnt;
310 CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
311 #ifdef PCNET_DEBUG_RMD_X
312 printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
313 PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
314 ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
315 PRINT_RMD(&rmd);
316 #endif
317 } else {
318 CSR_CRBC(s) = CSR_CRST(s) = 0;
319 }
321 if (CSR_NRDA(s)) {
322 struct pcnet_RMD rmd;
323 RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
324 CSR_NRBC(s) = rmd.rmd1.bcnt;
325 CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
326 } else {
327 CSR_NRBC(s) = CSR_NRST(s) = 0;
328 }
330 }
332 static int pcnet_tdte_poll(PCNetState *s)
333 {
334 s->csr[34] = s->csr[35] = 0;
335 if (s->tdra) {
336 target_phys_addr_t cxda = s->tdra +
337 (CSR_XMTRL(s) - CSR_XMTRC(s)) *
338 (BCR_SWSTYLE(s) ? 16 : 8 );
339 int bad = 0;
340 CHECK_TMD(PHYSADDR(s, cxda),bad);
341 if (!bad) {
342 if (CSR_CXDA(s) != cxda) {
343 s->csr[60] = s->csr[34];
344 s->csr[61] = s->csr[35];
345 s->csr[62] = CSR_CXBC(s);
346 s->csr[63] = CSR_CXST(s);
347 }
348 s->csr[34] = cxda & 0xffff;
349 s->csr[35] = cxda >> 16;
350 #ifdef PCNET_DEBUG
351 } else {
352 printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
353 #endif
354 }
355 }
357 if (CSR_CXDA(s)) {
358 struct pcnet_TMD tmd;
360 TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
362 CSR_CXBC(s) = tmd.tmd1.bcnt;
363 CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
364 } else {
365 CSR_CXBC(s) = CSR_CXST(s) = 0;
366 }
368 return !!(CSR_CXST(s) & 0x8000);
369 }
371 static int pcnet_can_receive(void *opaque)
372 {
373 PCNetState *s = opaque;
374 if (CSR_STOP(s) || CSR_SPND(s))
375 return 0;
377 if (s->recv_pos > 0)
378 return 0;
380 return sizeof(s->buffer)-16;
381 }
383 static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
384 {
385 PCNetState *s = opaque;
386 int is_padr = 0, is_bcast = 0, is_ladr = 0;
388 if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
389 return;
391 #ifdef PCNET_DEBUG
392 printf("pcnet_receive size=%d\n", size);
393 #endif
395 if (CSR_PROM(s)
396 || (is_padr=padr_match(s, buf, size))
397 || (is_bcast=padr_bcast(s, buf, size))
398 || (is_ladr=ladr_match(s, buf, size))) {
400 pcnet_rdte_poll(s);
402 if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
403 struct pcnet_RMD rmd;
404 int rcvrc = CSR_RCVRC(s)-1,i;
405 target_phys_addr_t nrda;
406 for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
407 if (rcvrc <= 1)
408 rcvrc = CSR_RCVRL(s);
409 nrda = s->rdra +
410 (CSR_RCVRL(s) - rcvrc) *
411 (BCR_SWSTYLE(s) ? 16 : 8 );
412 RMDLOAD(&rmd, PHYSADDR(s,nrda));
413 if (rmd.rmd1.own) {
414 #ifdef PCNET_DEBUG_RMD
415 printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
416 rcvrc, CSR_RCVRC(s));
417 #endif
418 CSR_RCVRC(s) = rcvrc;
419 pcnet_rdte_poll(s);
420 break;
421 }
422 }
423 }
425 if (!(CSR_CRST(s) & 0x8000)) {
426 #ifdef PCNET_DEBUG_RMD
427 printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
428 #endif
429 s->csr[0] |= 0x1000; /* Set MISS flag */
430 CSR_MISSC(s)++;
431 } else {
432 uint8_t *src = &s->buffer[8];
433 target_phys_addr_t crda = CSR_CRDA(s);
434 struct pcnet_RMD rmd;
435 int pktcount = 0;
437 memcpy(src, buf, size);
439 if (!CSR_ASTRP_RCV(s)) {
440 uint32_t fcs = ~0;
441 #if 0
442 uint8_t *p = s->buffer;
444 ((uint32_t *)p)[0] = ((uint32_t *)p)[1] = 0xaaaaaaaa;
445 p[7] = 0xab;
446 #else
447 uint8_t *p = src;
448 #endif
450 while (size < 46) {
451 src[size++] = 0;
452 }
454 while (p != &src[size]) {
455 CRC(fcs, *p++);
456 }
457 ((uint32_t *)&src[size])[0] = htonl(fcs);
458 size += 4; /* FCS at end of packet */
459 } else size += 4;
461 #ifdef PCNET_DEBUG_MATCH
462 PRINT_PKTHDR(buf);
463 #endif
465 RMDLOAD(&rmd, PHYSADDR(s,crda));
466 /*if (!CSR_LAPPEN(s))*/
467 rmd.rmd1.stp = 1;
469 #define PCNET_RECV_STORE() do { \
470 int count = MIN(4096 - rmd.rmd1.bcnt,size); \
471 target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
472 cpu_physical_memory_write(rbadr, src, count); \
473 cpu_physical_memory_set_dirty(rbadr); \
474 cpu_physical_memory_set_dirty(rbadr+count); \
475 src += count; size -= count; \
476 rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
477 RMDSTORE(&rmd, PHYSADDR(s,crda)); \
478 pktcount++; \
479 } while (0)
481 PCNET_RECV_STORE();
482 if ((size > 0) && CSR_NRDA(s)) {
483 target_phys_addr_t nrda = CSR_NRDA(s);
484 RMDLOAD(&rmd, PHYSADDR(s,nrda));
485 if (rmd.rmd1.own) {
486 crda = nrda;
487 PCNET_RECV_STORE();
488 if ((size > 0) && (nrda=CSR_NNRD(s))) {
489 RMDLOAD(&rmd, PHYSADDR(s,nrda));
490 if (rmd.rmd1.own) {
491 crda = nrda;
492 PCNET_RECV_STORE();
493 }
494 }
495 }
496 }
498 #undef PCNET_RECV_STORE
500 RMDLOAD(&rmd, PHYSADDR(s,crda));
501 if (size == 0) {
502 rmd.rmd1.enp = 1;
503 rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
504 rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
505 rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
506 } else {
507 rmd.rmd1.oflo = 1;
508 rmd.rmd1.buff = 1;
509 rmd.rmd1.err = 1;
510 }
511 RMDSTORE(&rmd, PHYSADDR(s,crda));
512 s->csr[0] |= 0x0400;
514 #ifdef PCNET_DEBUG
515 printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
516 CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
517 #endif
518 #ifdef PCNET_DEBUG_RMD
519 PRINT_RMD(&rmd);
520 #endif
522 while (pktcount--) {
523 if (CSR_RCVRC(s) <= 1)
524 CSR_RCVRC(s) = CSR_RCVRL(s);
525 else
526 CSR_RCVRC(s)--;
527 }
529 pcnet_rdte_poll(s);
531 }
532 }
534 pcnet_poll(s);
535 pcnet_update_irq(s);
536 }
538 static void pcnet_transmit(PCNetState *s)
539 {
540 target_phys_addr_t xmit_cxda = 0;
541 int count = CSR_XMTRL(s)-1;
542 s->xmit_pos = -1;
544 if (!CSR_TXON(s)) {
545 s->csr[0] &= ~0x0008;
546 return;
547 }
549 txagain:
550 if (pcnet_tdte_poll(s)) {
551 struct pcnet_TMD tmd;
553 TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
555 #ifdef PCNET_DEBUG_TMD
556 printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
557 PRINT_TMD(&tmd);
558 #endif
559 if (tmd.tmd1.stp) {
560 s->xmit_pos = 0;
561 if (!tmd.tmd1.enp) {
562 cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
563 s->buffer, 4096 - tmd.tmd1.bcnt);
564 s->xmit_pos += 4096 - tmd.tmd1.bcnt;
565 }
566 xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
567 }
568 if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
569 cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
570 s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
571 s->xmit_pos += 4096 - tmd.tmd1.bcnt;
573 tmd.tmd1.own = 0;
574 TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
576 #ifdef PCNET_DEBUG
577 printf("pcnet_transmit size=%d\n", s->xmit_pos);
578 #endif
579 if (CSR_LOOP(s))
580 pcnet_receive(s, s->buffer, s->xmit_pos);
581 else
582 qemu_send_packet(s->nd, s->buffer, s->xmit_pos);
584 s->csr[0] &= ~0x0008; /* clear TDMD */
585 s->csr[4] |= 0x0004; /* set TXSTRT */
586 s->xmit_pos = -1;
587 } else {
588 tmd.tmd1.own = 0;
589 TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
590 }
591 if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
592 s->csr[0] |= 0x0200; /* set TINT */
594 if (CSR_XMTRC(s)<=1)
595 CSR_XMTRC(s) = CSR_XMTRL(s);
596 else
597 CSR_XMTRC(s)--;
598 if (count--)
599 goto txagain;
601 } else
602 if (s->xmit_pos >= 0) {
603 struct pcnet_TMD tmd;
604 TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
605 tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
606 tmd.tmd1.own = 0;
607 TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
608 s->csr[0] |= 0x0200; /* set TINT */
609 if (!CSR_DXSUFLO(s)) {
610 s->csr[0] &= ~0x0010;
611 } else
612 if (count--)
613 goto txagain;
614 }
615 }
617 static void pcnet_poll(PCNetState *s)
618 {
619 if (CSR_RXON(s)) {
620 pcnet_rdte_poll(s);
621 }
623 if (CSR_TDMD(s) ||
624 (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
625 pcnet_transmit(s);
626 }
628 static void pcnet_poll_timer(void *opaque)
629 {
630 PCNetState *s = opaque;
632 qemu_del_timer(s->poll_timer);
634 if (CSR_TDMD(s)) {
635 pcnet_transmit(s);
636 }
638 pcnet_update_irq(s);
640 if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
641 uint64_t now = qemu_get_clock(vm_clock) * 33;
642 if (!s->timer || !now)
643 s->timer = now;
644 else {
645 uint64_t t = now - s->timer + CSR_POLL(s);
646 if (t > 0xffffLL) {
647 pcnet_poll(s);
648 CSR_POLL(s) = CSR_PINT(s);
649 } else
650 CSR_POLL(s) = t;
651 }
652 qemu_mod_timer(s->poll_timer,
653 pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
654 }
655 }
658 static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
659 {
660 uint16_t val = new_value;
661 #ifdef PCNET_DEBUG_CSR
662 printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
663 #endif
664 switch (rap) {
665 case 0:
666 s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
668 s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
670 val = (val & 0x007f) | (s->csr[0] & 0x7f00);
672 /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
673 if ((val&7) == 7)
674 val &= ~3;
676 if (!CSR_STOP(s) && (val & 4))
677 pcnet_stop(s);
679 if (!CSR_INIT(s) && (val & 1))
680 pcnet_init(s);
682 if (!CSR_STRT(s) && (val & 2))
683 pcnet_start(s);
685 if (CSR_TDMD(s))
686 pcnet_transmit(s);
688 return;
689 case 1:
690 case 2:
691 case 8:
692 case 9:
693 case 10:
694 case 11:
695 case 12:
696 case 13:
697 case 14:
698 case 15:
699 case 18: /* CRBAL */
700 case 19: /* CRBAU */
701 case 20: /* CXBAL */
702 case 21: /* CXBAU */
703 case 22: /* NRBAU */
704 case 23: /* NRBAU */
705 case 24:
706 case 25:
707 case 26:
708 case 27:
709 case 28:
710 case 29:
711 case 30:
712 case 31:
713 case 32:
714 case 33:
715 case 34:
716 case 35:
717 case 36:
718 case 37:
719 case 38:
720 case 39:
721 case 40: /* CRBC */
722 case 41:
723 case 42: /* CXBC */
724 case 43:
725 case 44:
726 case 45:
727 case 46: /* POLL */
728 case 47: /* POLLINT */
729 case 72:
730 case 74:
731 case 76: /* RCVRL */
732 case 78: /* XMTRL */
733 case 112:
734 if (CSR_STOP(s) || CSR_SPND(s))
735 break;
736 return;
737 case 3:
738 break;
739 case 4:
740 s->csr[4] &= ~(val & 0x026a);
741 val &= ~0x026a; val |= s->csr[4] & 0x026a;
742 break;
743 case 5:
744 s->csr[5] &= ~(val & 0x0a90);
745 val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
746 break;
747 case 16:
748 pcnet_csr_writew(s,1,val);
749 return;
750 case 17:
751 pcnet_csr_writew(s,2,val);
752 return;
753 case 58:
754 pcnet_bcr_writew(s,BCR_SWS,val);
755 break;
756 default:
757 return;
758 }
759 s->csr[rap] = val;
760 }
762 static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
763 {
764 uint32_t val;
765 switch (rap) {
766 case 0:
767 pcnet_update_irq(s);
768 val = s->csr[0];
769 val |= (val & 0x7800) ? 0x8000 : 0;
770 break;
771 case 16:
772 return pcnet_csr_readw(s,1);
773 case 17:
774 return pcnet_csr_readw(s,2);
775 case 58:
776 return pcnet_bcr_readw(s,BCR_SWS);
777 case 88:
778 val = s->csr[89];
779 val <<= 16;
780 val |= s->csr[88];
781 break;
782 default:
783 val = s->csr[rap];
784 }
785 #ifdef PCNET_DEBUG_CSR
786 printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
787 #endif
788 return val;
789 }
791 static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
792 {
793 rap &= 127;
794 #ifdef PCNET_DEBUG_BCR
795 printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
796 #endif
797 switch (rap) {
798 case BCR_SWS:
799 if (!(CSR_STOP(s) || CSR_SPND(s)))
800 return;
801 val &= ~0x0300;
802 switch (val & 0x00ff) {
803 case 0:
804 val |= 0x0200;
805 break;
806 case 1:
807 val |= 0x0100;
808 break;
809 case 2:
810 case 3:
811 val |= 0x0300;
812 break;
813 default:
814 printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
815 val = 0x0200;
816 break;
817 }
818 #ifdef PCNET_DEBUG
819 printf("BCR_SWS=0x%04x\n", val);
820 #endif
821 case BCR_LNKST:
822 case BCR_LED1:
823 case BCR_LED2:
824 case BCR_LED3:
825 case BCR_MC:
826 case BCR_FDC:
827 case BCR_BSBC:
828 case BCR_EECAS:
829 case BCR_PLAT:
830 s->bcr[rap] = val;
831 break;
832 default:
833 break;
834 }
835 }
837 static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
838 {
839 uint32_t val;
840 rap &= 127;
841 switch (rap) {
842 case BCR_LNKST:
843 case BCR_LED1:
844 case BCR_LED2:
845 case BCR_LED3:
846 val = s->bcr[rap] & ~0x8000;
847 val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
848 break;
849 default:
850 val = rap < 32 ? s->bcr[rap] : 0;
851 break;
852 }
853 #ifdef PCNET_DEBUG_BCR
854 printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
855 #endif
856 return val;
857 }
859 static void pcnet_h_reset(PCNetState *s)
860 {
861 int i;
862 uint16_t checksum;
864 /* Initialize the PROM */
866 memcpy(s->prom, s->nd->macaddr, 6);
867 s->prom[12] = s->prom[13] = 0x00;
868 s->prom[14] = s->prom[15] = 0x57;
870 for (i = 0,checksum = 0; i < 16; i++)
871 checksum += s->prom[i];
872 *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
875 s->bcr[BCR_MSRDA] = 0x0005;
876 s->bcr[BCR_MSWRA] = 0x0005;
877 s->bcr[BCR_MC ] = 0x0002;
878 s->bcr[BCR_LNKST] = 0x00c0;
879 s->bcr[BCR_LED1 ] = 0x0084;
880 s->bcr[BCR_LED2 ] = 0x0088;
881 s->bcr[BCR_LED3 ] = 0x0090;
882 s->bcr[BCR_FDC ] = 0x0000;
883 s->bcr[BCR_BSBC ] = 0x9001;
884 s->bcr[BCR_EECAS] = 0x0002;
885 s->bcr[BCR_SWS ] = 0x0200;
886 s->bcr[BCR_PLAT ] = 0xff06;
888 pcnet_s_reset(s);
889 }
891 static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
892 {
893 PCNetState *s = opaque;
894 #ifdef PCNET_DEBUG
895 printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
896 #endif
897 /* Check APROMWE bit to enable write access */
898 if (pcnet_bcr_readw(s,2) & 0x80)
899 s->prom[addr & 15] = val;
900 }
902 static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
903 {
904 PCNetState *s = opaque;
905 uint32_t val = s->prom[addr &= 15];
906 #ifdef PCNET_DEBUG
907 printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
908 #endif
909 return val;
910 }
912 static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
913 {
914 PCNetState *s = opaque;
915 pcnet_poll_timer(s);
916 #ifdef PCNET_DEBUG_IO
917 printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
918 #endif
919 if (!BCR_DWIO(s)) {
920 switch (addr & 0x0f) {
921 case 0x00: /* RDP */
922 pcnet_csr_writew(s, s->rap, val);
923 break;
924 case 0x02:
925 s->rap = val & 0x7f;
926 break;
927 case 0x06:
928 pcnet_bcr_writew(s, s->rap, val);
929 break;
930 }
931 }
932 pcnet_update_irq(s);
933 }
935 static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
936 {
937 PCNetState *s = opaque;
938 uint32_t val = -1;
939 pcnet_poll_timer(s);
940 if (!BCR_DWIO(s)) {
941 switch (addr & 0x0f) {
942 case 0x00: /* RDP */
943 val = pcnet_csr_readw(s, s->rap);
944 break;
945 case 0x02:
946 val = s->rap;
947 break;
948 case 0x04:
949 pcnet_s_reset(s);
950 val = 0;
951 break;
952 case 0x06:
953 val = pcnet_bcr_readw(s, s->rap);
954 break;
955 }
956 }
957 pcnet_update_irq(s);
958 #ifdef PCNET_DEBUG_IO
959 printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
960 #endif
961 return val;
962 }
964 static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
965 {
966 PCNetState *s = opaque;
967 pcnet_poll_timer(s);
968 #ifdef PCNET_DEBUG_IO
969 printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
970 #endif
971 if (BCR_DWIO(s)) {
972 switch (addr & 0x0f) {
973 case 0x00: /* RDP */
974 pcnet_csr_writew(s, s->rap, val & 0xffff);
975 break;
976 case 0x04:
977 s->rap = val & 0x7f;
978 break;
979 case 0x0c:
980 pcnet_bcr_writew(s, s->rap, val & 0xffff);
981 break;
982 }
983 } else
984 if ((addr & 0x0f) == 0) {
985 /* switch device to dword i/o mode */
986 pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
987 #ifdef PCNET_DEBUG_IO
988 printf("device switched into dword i/o mode\n");
989 #endif
990 }
991 pcnet_update_irq(s);
992 }
994 static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
995 {
996 PCNetState *s = opaque;
997 uint32_t val = -1;
998 pcnet_poll_timer(s);
999 if (BCR_DWIO(s)) {
1000 switch (addr & 0x0f) {
1001 case 0x00: /* RDP */
1002 val = pcnet_csr_readw(s, s->rap);
1003 break;
1004 case 0x04:
1005 val = s->rap;
1006 break;
1007 case 0x08:
1008 pcnet_s_reset(s);
1009 val = 0;
1010 break;
1011 case 0x0c:
1012 val = pcnet_bcr_readw(s, s->rap);
1013 break;
1016 pcnet_update_irq(s);
1017 #ifdef PCNET_DEBUG_IO
1018 printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
1019 #endif
1020 return val;
1023 static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
1024 uint32_t addr, uint32_t size, int type)
1026 PCNetState *d = (PCNetState *)pci_dev;
1028 #ifdef PCNET_DEBUG_IO
1029 printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
1030 #endif
1032 register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
1033 register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
1035 register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
1036 register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
1037 register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
1038 register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
1041 static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
1043 PCNetState *d = opaque;
1044 #ifdef PCNET_DEBUG_IO
1045 printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val);
1046 #endif
1047 if (!(addr & 0x10))
1048 pcnet_aprom_writeb(d, addr & 0x0f, val);
1051 static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
1053 PCNetState *d = opaque;
1054 uint32_t val = -1;
1055 if (!(addr & 0x10))
1056 val = pcnet_aprom_readb(d, addr & 0x0f);
1057 #ifdef PCNET_DEBUG_IO
1058 printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff);
1059 #endif
1060 return val;
1063 static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
1065 PCNetState *d = opaque;
1066 #ifdef PCNET_DEBUG_IO
1067 printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);
1068 #endif
1069 if (addr & 0x10)
1070 pcnet_ioport_writew(d, addr & 0x0f, val);
1071 else {
1072 addr &= 0x0f;
1073 pcnet_aprom_writeb(d, addr, val & 0xff);
1074 pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
1078 static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
1080 PCNetState *d = opaque;
1081 uint32_t val = -1;
1082 if (addr & 0x10)
1083 val = pcnet_ioport_readw(d, addr & 0x0f);
1084 else {
1085 addr &= 0x0f;
1086 val = pcnet_aprom_readb(d, addr+1);
1087 val <<= 8;
1088 val |= pcnet_aprom_readb(d, addr);
1090 #ifdef PCNET_DEBUG_IO
1091 printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff);
1092 #endif
1093 return val;
1096 static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
1098 PCNetState *d = opaque;
1099 #ifdef PCNET_DEBUG_IO
1100 printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val);
1101 #endif
1102 if (addr & 0x10)
1103 pcnet_ioport_writel(d, addr & 0x0f, val);
1104 else {
1105 addr &= 0x0f;
1106 pcnet_aprom_writeb(d, addr, val & 0xff);
1107 pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
1108 pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
1109 pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
1113 static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
1115 PCNetState *d = opaque;
1116 uint32_t val;
1117 if (addr & 0x10)
1118 val = pcnet_ioport_readl(d, addr & 0x0f);
1119 else {
1120 addr &= 0x0f;
1121 val = pcnet_aprom_readb(d, addr+3);
1122 val <<= 8;
1123 val |= pcnet_aprom_readb(d, addr+2);
1124 val <<= 8;
1125 val |= pcnet_aprom_readb(d, addr+1);
1126 val <<= 8;
1127 val |= pcnet_aprom_readb(d, addr);
1129 #ifdef PCNET_DEBUG_IO
1130 printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val);
1131 #endif
1132 return val;
1136 static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
1137 (CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
1138 (CPUWriteMemoryFunc *)&pcnet_mmio_writew,
1139 (CPUWriteMemoryFunc *)&pcnet_mmio_writel
1140 };
1142 static CPUReadMemoryFunc *pcnet_mmio_read[] = {
1143 (CPUReadMemoryFunc *)&pcnet_mmio_readb,
1144 (CPUReadMemoryFunc *)&pcnet_mmio_readw,
1145 (CPUReadMemoryFunc *)&pcnet_mmio_readl
1146 };
1148 static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
1149 uint32_t addr, uint32_t size, int type)
1151 PCNetState *d = (PCNetState *)pci_dev;
1153 #ifdef PCNET_DEBUG_IO
1154 printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);
1155 #endif
1157 cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
1160 void pci_pcnet_init(PCIBus *bus, NetDriverState *nd)
1162 PCNetState *d;
1163 uint8_t *pci_conf;
1165 #if 0
1166 printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
1167 sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
1168 #endif
1170 d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
1171 -1, NULL, NULL);
1173 pci_conf = d->dev.config;
1175 *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
1176 *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
1177 *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
1178 *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
1179 pci_conf[0x08] = 0x10;
1180 pci_conf[0x09] = 0x00;
1181 pci_conf[0x0a] = 0x00; // ethernet network controller
1182 pci_conf[0x0b] = 0x02;
1183 pci_conf[0x0e] = 0x00; // header_type
1185 *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
1186 *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
1188 pci_conf[0x3d] = 1; // interrupt pin 0
1189 pci_conf[0x3e] = 0x06;
1190 pci_conf[0x3f] = 0xff;
1192 /* Handler for memory-mapped I/O */
1193 d->mmio_io_addr =
1194 cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
1196 pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
1197 PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
1199 pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
1200 PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
1202 d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
1204 d->nd = nd;
1206 pcnet_h_reset(d);
1208 qemu_add_read_packet(nd, pcnet_can_receive, pcnet_receive, d);