|
|
1.1 root 1: /*
2: * QEMU AMD PC-Net II (Am79C970A) emulation
1.1.1.3 root 3: *
1.1 root 4: * Copyright (c) 2004 Antony T Curtis
1.1.1.3 root 5: *
1.1 root 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: */
1.1.1.3 root 24:
1.1 root 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: */
1.1.1.3 root 29:
1.1.1.2 root 30: /*
31: * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
32: * produced as NCR89C100. See
33: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
34: * and
35: * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
36: */
37:
1.1.1.10 root 38: #include "qdev.h"
1.1.1.3 root 39: #include "net.h"
40: #include "qemu-timer.h"
1.1.1.4 root 41: #include "qemu_socket.h"
1.1.1.10 root 42: #include "sysemu.h"
1.1 root 43:
1.1.1.8 root 44: #include "pcnet.h"
45:
1.1 root 46: //#define PCNET_DEBUG
47: //#define PCNET_DEBUG_IO
48: //#define PCNET_DEBUG_BCR
49: //#define PCNET_DEBUG_CSR
50: //#define PCNET_DEBUG_RMD
51: //#define PCNET_DEBUG_TMD
52: //#define PCNET_DEBUG_MATCH
53:
54:
55: struct qemu_ether_header {
56: uint8_t ether_dhost[6];
57: uint8_t ether_shost[6];
58: uint16_t ether_type;
59: };
60:
61: #define CSR_INIT(S) !!(((S)->csr[0])&0x0001)
62: #define CSR_STRT(S) !!(((S)->csr[0])&0x0002)
63: #define CSR_STOP(S) !!(((S)->csr[0])&0x0004)
64: #define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)
65: #define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
66: #define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
67: #define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
1.1.1.2 root 68: #define CSR_BSWP(S) !!(((S)->csr[3])&0x0004)
1.1 root 69: #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
70: #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
71: #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
72: #define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)
73: #define CSR_SPND(S) !!(((S)->csr[5])&0x0001)
74: #define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)
75: #define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)
76: #define CSR_DRX(S) !!(((S)->csr[15])&0x0001)
77: #define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
78: #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
1.1.1.4 root 79: #define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008)
1.1.1.13! root 80: #define CSR_INTL(S) !!(((S)->csr[15])&0x0040)
1.1 root 81: #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
82: #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
83: #define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
84:
85: #define CSR_CRBC(S) ((S)->csr[40])
86: #define CSR_CRST(S) ((S)->csr[41])
87: #define CSR_CXBC(S) ((S)->csr[42])
88: #define CSR_CXST(S) ((S)->csr[43])
89: #define CSR_NRBC(S) ((S)->csr[44])
90: #define CSR_NRST(S) ((S)->csr[45])
91: #define CSR_POLL(S) ((S)->csr[46])
92: #define CSR_PINT(S) ((S)->csr[47])
93: #define CSR_RCVRC(S) ((S)->csr[72])
94: #define CSR_XMTRC(S) ((S)->csr[74])
95: #define CSR_RCVRL(S) ((S)->csr[76])
96: #define CSR_XMTRL(S) ((S)->csr[78])
97: #define CSR_MISSC(S) ((S)->csr[112])
98:
1.1.1.11 root 99: #define CSR_IADR(S) ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
100: #define CSR_CRBA(S) ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
101: #define CSR_CXBA(S) ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
102: #define CSR_NRBA(S) ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
103: #define CSR_BADR(S) ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
104: #define CSR_NRDA(S) ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
105: #define CSR_CRDA(S) ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
106: #define CSR_BADX(S) ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
107: #define CSR_NXDA(S) ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
108: #define CSR_CXDA(S) ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
109: #define CSR_NNRD(S) ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
110: #define CSR_NNXD(S) ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
111: #define CSR_PXDA(S) ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
112: #define CSR_NXBA(S) ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
1.1 root 113:
114: #define PHYSADDR(S,A) \
1.1.1.11 root 115: (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
1.1 root 116:
117: struct pcnet_initblk16 {
118: uint16_t mode;
1.1.1.2 root 119: uint16_t padr[3];
120: uint16_t ladrf[4];
121: uint32_t rdra;
122: uint32_t tdra;
1.1 root 123: };
124:
125: struct pcnet_initblk32 {
126: uint16_t mode;
1.1.1.2 root 127: uint8_t rlen;
128: uint8_t tlen;
129: uint16_t padr[3];
1.1 root 130: uint16_t _res;
1.1.1.2 root 131: uint16_t ladrf[4];
1.1 root 132: uint32_t rdra;
133: uint32_t tdra;
134: };
135:
136: struct pcnet_TMD {
1.1.1.3 root 137: uint32_t tbadr;
138: int16_t length;
139: int16_t status;
140: uint32_t misc;
141: uint32_t res;
1.1 root 142: };
143:
1.1.1.3 root 144: #define TMDL_BCNT_MASK 0x0fff
145: #define TMDL_BCNT_SH 0
146: #define TMDL_ONES_MASK 0xf000
147: #define TMDL_ONES_SH 12
148:
149: #define TMDS_BPE_MASK 0x0080
150: #define TMDS_BPE_SH 7
151: #define TMDS_ENP_MASK 0x0100
152: #define TMDS_ENP_SH 8
153: #define TMDS_STP_MASK 0x0200
154: #define TMDS_STP_SH 9
155: #define TMDS_DEF_MASK 0x0400
156: #define TMDS_DEF_SH 10
157: #define TMDS_ONE_MASK 0x0800
158: #define TMDS_ONE_SH 11
159: #define TMDS_LTINT_MASK 0x1000
160: #define TMDS_LTINT_SH 12
161: #define TMDS_NOFCS_MASK 0x2000
162: #define TMDS_NOFCS_SH 13
1.1.1.4 root 163: #define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
164: #define TMDS_ADDFCS_SH TMDS_NOFCS_SH
1.1.1.3 root 165: #define TMDS_ERR_MASK 0x4000
166: #define TMDS_ERR_SH 14
167: #define TMDS_OWN_MASK 0x8000
168: #define TMDS_OWN_SH 15
169:
170: #define TMDM_TRC_MASK 0x0000000f
171: #define TMDM_TRC_SH 0
172: #define TMDM_TDR_MASK 0x03ff0000
173: #define TMDM_TDR_SH 16
174: #define TMDM_RTRY_MASK 0x04000000
175: #define TMDM_RTRY_SH 26
176: #define TMDM_LCAR_MASK 0x08000000
177: #define TMDM_LCAR_SH 27
178: #define TMDM_LCOL_MASK 0x10000000
179: #define TMDM_LCOL_SH 28
180: #define TMDM_EXDEF_MASK 0x20000000
181: #define TMDM_EXDEF_SH 29
182: #define TMDM_UFLO_MASK 0x40000000
183: #define TMDM_UFLO_SH 30
184: #define TMDM_BUFF_MASK 0x80000000
185: #define TMDM_BUFF_SH 31
186:
1.1 root 187: struct pcnet_RMD {
1.1.1.3 root 188: uint32_t rbadr;
189: int16_t buf_length;
190: int16_t status;
191: uint32_t msg_length;
192: uint32_t res;
1.1 root 193: };
194:
1.1.1.3 root 195: #define RMDL_BCNT_MASK 0x0fff
196: #define RMDL_BCNT_SH 0
197: #define RMDL_ONES_MASK 0xf000
198: #define RMDL_ONES_SH 12
199:
200: #define RMDS_BAM_MASK 0x0010
201: #define RMDS_BAM_SH 4
202: #define RMDS_LFAM_MASK 0x0020
203: #define RMDS_LFAM_SH 5
204: #define RMDS_PAM_MASK 0x0040
205: #define RMDS_PAM_SH 6
206: #define RMDS_BPE_MASK 0x0080
207: #define RMDS_BPE_SH 7
208: #define RMDS_ENP_MASK 0x0100
209: #define RMDS_ENP_SH 8
210: #define RMDS_STP_MASK 0x0200
211: #define RMDS_STP_SH 9
212: #define RMDS_BUFF_MASK 0x0400
213: #define RMDS_BUFF_SH 10
214: #define RMDS_CRC_MASK 0x0800
215: #define RMDS_CRC_SH 11
216: #define RMDS_OFLO_MASK 0x1000
217: #define RMDS_OFLO_SH 12
218: #define RMDS_FRAM_MASK 0x2000
219: #define RMDS_FRAM_SH 13
220: #define RMDS_ERR_MASK 0x4000
221: #define RMDS_ERR_SH 14
222: #define RMDS_OWN_MASK 0x8000
223: #define RMDS_OWN_SH 15
224:
225: #define RMDM_MCNT_MASK 0x00000fff
226: #define RMDM_MCNT_SH 0
227: #define RMDM_ZEROS_MASK 0x0000f000
228: #define RMDM_ZEROS_SH 12
229: #define RMDM_RPC_MASK 0x00ff0000
230: #define RMDM_RPC_SH 16
231: #define RMDM_RCC_MASK 0xff000000
232: #define RMDM_RCC_SH 24
233:
234: #define SET_FIELD(regp, name, field, value) \
235: (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
236: | ((value) << name ## _ ## field ## _SH))
237:
238: #define GET_FIELD(reg, name, field) \
239: (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
1.1 root 240:
1.1.1.3 root 241: #define PRINT_TMD(T) printf( \
242: "TMD0 : TBADR=0x%08x\n" \
1.1 root 243: "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
244: "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
245: " BPE=%d, BCNT=%d\n" \
246: "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
247: "LCA=%d, RTR=%d,\n" \
248: " TDR=%d, TRC=%d\n", \
1.1.1.3 root 249: (T)->tbadr, \
250: GET_FIELD((T)->status, TMDS, OWN), \
251: GET_FIELD((T)->status, TMDS, ERR), \
252: GET_FIELD((T)->status, TMDS, NOFCS), \
253: GET_FIELD((T)->status, TMDS, LTINT), \
254: GET_FIELD((T)->status, TMDS, ONE), \
255: GET_FIELD((T)->status, TMDS, DEF), \
256: GET_FIELD((T)->status, TMDS, STP), \
257: GET_FIELD((T)->status, TMDS, ENP), \
258: GET_FIELD((T)->status, TMDS, BPE), \
259: 4096-GET_FIELD((T)->length, TMDL, BCNT), \
260: GET_FIELD((T)->misc, TMDM, BUFF), \
261: GET_FIELD((T)->misc, TMDM, UFLO), \
262: GET_FIELD((T)->misc, TMDM, EXDEF), \
263: GET_FIELD((T)->misc, TMDM, LCOL), \
264: GET_FIELD((T)->misc, TMDM, LCAR), \
265: GET_FIELD((T)->misc, TMDM, RTRY), \
266: GET_FIELD((T)->misc, TMDM, TDR), \
267: GET_FIELD((T)->misc, TMDM, TRC))
1.1 root 268:
1.1.1.3 root 269: #define PRINT_RMD(R) printf( \
270: "RMD0 : RBADR=0x%08x\n" \
1.1 root 271: "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
272: "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
1.1.1.3 root 273: "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
1.1 root 274: "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
1.1.1.3 root 275: (R)->rbadr, \
276: GET_FIELD((R)->status, RMDS, OWN), \
277: GET_FIELD((R)->status, RMDS, ERR), \
278: GET_FIELD((R)->status, RMDS, FRAM), \
279: GET_FIELD((R)->status, RMDS, OFLO), \
280: GET_FIELD((R)->status, RMDS, CRC), \
281: GET_FIELD((R)->status, RMDS, BUFF), \
282: GET_FIELD((R)->status, RMDS, STP), \
283: GET_FIELD((R)->status, RMDS, ENP), \
284: GET_FIELD((R)->status, RMDS, BPE), \
285: GET_FIELD((R)->status, RMDS, PAM), \
286: GET_FIELD((R)->status, RMDS, LFAM), \
287: GET_FIELD((R)->status, RMDS, BAM), \
288: GET_FIELD((R)->buf_length, RMDL, ONES), \
289: 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \
290: GET_FIELD((R)->msg_length, RMDM, RCC), \
291: GET_FIELD((R)->msg_length, RMDM, RPC), \
292: GET_FIELD((R)->msg_length, RMDM, MCNT), \
293: GET_FIELD((R)->msg_length, RMDM, ZEROS))
1.1 root 294:
1.1.1.3 root 295: static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
1.1.1.2 root 296: target_phys_addr_t addr)
1.1 root 297: {
1.1.1.3 root 298: if (!BCR_SSIZE32(s)) {
299: struct {
300: uint32_t tbadr;
301: int16_t length;
302: int16_t status;
303: } xda;
304: s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
305: tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
306: tmd->length = le16_to_cpu(xda.length);
307: tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
308: tmd->misc = le16_to_cpu(xda.status) << 16;
309: tmd->res = 0;
1.1.1.2 root 310: } else {
1.1.1.3 root 311: s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
312: le32_to_cpus(&tmd->tbadr);
313: le16_to_cpus((uint16_t *)&tmd->length);
314: le16_to_cpus((uint16_t *)&tmd->status);
315: le32_to_cpus(&tmd->misc);
316: le32_to_cpus(&tmd->res);
317: if (BCR_SWSTYLE(s) == 3) {
318: uint32_t tmp = tmd->tbadr;
319: tmd->tbadr = tmd->misc;
320: tmd->misc = tmp;
1.1.1.2 root 321: }
1.1 root 322: }
323: }
324:
1.1.1.3 root 325: static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
1.1.1.2 root 326: target_phys_addr_t addr)
1.1 root 327: {
1.1.1.3 root 328: if (!BCR_SSIZE32(s)) {
329: struct {
330: uint32_t tbadr;
331: int16_t length;
332: int16_t status;
333: } xda;
334: xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
335: ((tmd->status & 0xff00) << 16));
336: xda.length = cpu_to_le16(tmd->length);
337: xda.status = cpu_to_le16(tmd->misc >> 16);
338: s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
1.1.1.2 root 339: } else {
1.1.1.3 root 340: struct {
341: uint32_t tbadr;
342: int16_t length;
343: int16_t status;
344: uint32_t misc;
345: uint32_t res;
346: } xda;
347: xda.tbadr = cpu_to_le32(tmd->tbadr);
348: xda.length = cpu_to_le16(tmd->length);
349: xda.status = cpu_to_le16(tmd->status);
350: xda.misc = cpu_to_le32(tmd->misc);
351: xda.res = cpu_to_le32(tmd->res);
352: if (BCR_SWSTYLE(s) == 3) {
353: uint32_t tmp = xda.tbadr;
354: xda.tbadr = xda.misc;
355: xda.misc = tmp;
1.1 root 356: }
1.1.1.3 root 357: s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
1.1 root 358: }
359: }
360:
1.1.1.3 root 361: static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
1.1.1.2 root 362: target_phys_addr_t addr)
1.1 root 363: {
1.1.1.3 root 364: if (!BCR_SSIZE32(s)) {
365: struct {
366: uint32_t rbadr;
367: int16_t buf_length;
368: int16_t msg_length;
369: } rda;
370: s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
371: rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
372: rmd->buf_length = le16_to_cpu(rda.buf_length);
373: rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
374: rmd->msg_length = le16_to_cpu(rda.msg_length);
375: rmd->res = 0;
1.1.1.2 root 376: } else {
1.1.1.3 root 377: s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
378: le32_to_cpus(&rmd->rbadr);
379: le16_to_cpus((uint16_t *)&rmd->buf_length);
380: le16_to_cpus((uint16_t *)&rmd->status);
381: le32_to_cpus(&rmd->msg_length);
382: le32_to_cpus(&rmd->res);
383: if (BCR_SWSTYLE(s) == 3) {
384: uint32_t tmp = rmd->rbadr;
385: rmd->rbadr = rmd->msg_length;
386: rmd->msg_length = tmp;
1.1.1.2 root 387: }
1.1 root 388: }
389: }
390:
1.1.1.3 root 391: static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
1.1.1.2 root 392: target_phys_addr_t addr)
1.1 root 393: {
1.1.1.3 root 394: if (!BCR_SSIZE32(s)) {
395: struct {
396: uint32_t rbadr;
397: int16_t buf_length;
398: int16_t msg_length;
399: } rda;
400: rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
401: ((rmd->status & 0xff00) << 16));
402: rda.buf_length = cpu_to_le16(rmd->buf_length);
403: rda.msg_length = cpu_to_le16(rmd->msg_length);
404: s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
1.1.1.2 root 405: } else {
1.1.1.3 root 406: struct {
407: uint32_t rbadr;
408: int16_t buf_length;
409: int16_t status;
410: uint32_t msg_length;
411: uint32_t res;
412: } rda;
413: rda.rbadr = cpu_to_le32(rmd->rbadr);
414: rda.buf_length = cpu_to_le16(rmd->buf_length);
415: rda.status = cpu_to_le16(rmd->status);
416: rda.msg_length = cpu_to_le32(rmd->msg_length);
417: rda.res = cpu_to_le32(rmd->res);
418: if (BCR_SWSTYLE(s) == 3) {
419: uint32_t tmp = rda.rbadr;
420: rda.rbadr = rda.msg_length;
421: rda.msg_length = tmp;
1.1 root 422: }
1.1.1.3 root 423: s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
1.1 root 424: }
425: }
426:
427:
428: #define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
429:
430: #define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
431:
432: #define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
433:
434: #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
435:
436: #if 1
437:
438: #define CHECK_RMD(ADDR,RES) do { \
439: struct pcnet_RMD rmd; \
440: RMDLOAD(&rmd,(ADDR)); \
1.1.1.3 root 441: (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
442: || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
1.1 root 443: } while (0)
444:
445: #define CHECK_TMD(ADDR,RES) do { \
446: struct pcnet_TMD tmd; \
447: TMDLOAD(&tmd,(ADDR)); \
1.1.1.3 root 448: (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
1.1 root 449: } while (0)
450:
451: #else
452:
453: #define CHECK_RMD(ADDR,RES) do { \
454: switch (BCR_SWSTYLE(s)) { \
455: case 0x00: \
456: do { \
457: uint16_t rda[4]; \
1.1.1.3 root 458: s->phys_mem_read(s->dma_opaque, (ADDR), \
459: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 460: (RES) |= (rda[2] & 0xf000)!=0xf000; \
461: (RES) |= (rda[3] & 0xf000)!=0x0000; \
462: } while (0); \
463: break; \
464: case 0x01: \
465: case 0x02: \
466: do { \
467: uint32_t rda[4]; \
1.1.1.3 root 468: s->phys_mem_read(s->dma_opaque, (ADDR), \
1.1.1.2 root 469: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 470: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
471: (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
472: } while (0); \
473: break; \
474: case 0x03: \
475: do { \
476: uint32_t rda[4]; \
1.1.1.3 root 477: s->phys_mem_read(s->dma_opaque, (ADDR), \
1.1.1.2 root 478: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 479: (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
480: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
481: } while (0); \
482: break; \
483: } \
484: } while (0)
485:
486: #define CHECK_TMD(ADDR,RES) do { \
487: switch (BCR_SWSTYLE(s)) { \
488: case 0x00: \
489: do { \
490: uint16_t xda[4]; \
1.1.1.3 root 491: s->phys_mem_read(s->dma_opaque, (ADDR), \
492: (void *)&xda[0], sizeof(xda), 0); \
493: (RES) |= (xda[2] & 0xf000)!=0xf000; \
1.1 root 494: } while (0); \
495: break; \
496: case 0x01: \
497: case 0x02: \
498: case 0x03: \
499: do { \
500: uint32_t xda[4]; \
1.1.1.3 root 501: s->phys_mem_read(s->dma_opaque, (ADDR), \
502: (void *)&xda[0], sizeof(xda), 0); \
1.1 root 503: (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
504: } while (0); \
505: break; \
506: } \
507: } while (0)
508:
509: #endif
510:
511: #define PRINT_PKTHDR(BUF) do { \
1.1.1.3 root 512: struct qemu_ether_header *hdr = (void *)(BUF); \
513: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
514: "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
515: "type=0x%04x\n", \
1.1 root 516: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
517: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
518: hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
519: hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
1.1.1.3 root 520: be16_to_cpu(hdr->ether_type)); \
1.1 root 521: } while (0)
522:
523: #define MULTICAST_FILTER_LEN 8
524:
525: static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
526: {
527: #define LNC_POLYNOMIAL 0xEDB88320UL
528: uint32_t crc = 0xFFFFFFFF;
529: int idx, bit;
530: uint8_t data;
531:
532: for (idx = 0; idx < 6; idx++) {
533: for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
534: crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
535: data >>= 1;
536: }
537: }
538: return crc;
539: #undef LNC_POLYNOMIAL
540: }
541:
542: #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
543:
544: /* generated using the AUTODIN II polynomial
545: * x^32 + x^26 + x^23 + x^22 + x^16 +
546: * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
547: */
548: static const uint32_t crctab[256] = {
549: 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
550: 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
551: 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
552: 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
553: 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
554: 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
555: 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
556: 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
557: 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
558: 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
559: 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
560: 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
561: 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
562: 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
563: 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
564: 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
565: 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
566: 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
567: 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
568: 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
569: 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
570: 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
571: 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
572: 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
573: 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
574: 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
575: 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
576: 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
577: 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
578: 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
579: 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
580: 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
581: 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
582: 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
583: 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
584: 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
585: 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
586: 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
587: 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
588: 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
589: 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
590: 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
591: 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
592: 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
593: 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
594: 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
595: 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
596: 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
597: 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
598: 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
599: 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
600: 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
601: 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
602: 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
603: 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
604: 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
605: 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
606: 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
607: 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
608: 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
609: 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
610: 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
611: 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
612: 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
613: };
614:
615: static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
616: {
617: struct qemu_ether_header *hdr = (void *)buf;
1.1.1.3 root 618: uint8_t padr[6] = {
1.1 root 619: s->csr[12] & 0xff, s->csr[12] >> 8,
620: s->csr[13] & 0xff, s->csr[13] >> 8,
1.1.1.3 root 621: s->csr[14] & 0xff, s->csr[14] >> 8
1.1 root 622: };
623: int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
624: #ifdef PCNET_DEBUG_MATCH
625: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
626: "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
627: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
628: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
629: padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
630: printf("padr_match result=%d\n", result);
631: #endif
632: return result;
633: }
634:
635: static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
636: {
1.1.1.2 root 637: static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1.1 root 638: struct qemu_ether_header *hdr = (void *)buf;
639: int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
640: #ifdef PCNET_DEBUG_MATCH
641: printf("padr_bcast result=%d\n", result);
642: #endif
643: return result;
644: }
645:
646: static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
647: {
648: struct qemu_ether_header *hdr = (void *)buf;
1.1.1.3 root 649: if ((*(hdr->ether_dhost)&0x01) &&
1.1 root 650: ((uint64_t *)&s->csr[8])[0] != 0LL) {
1.1.1.3 root 651: uint8_t ladr[8] = {
1.1 root 652: s->csr[8] & 0xff, s->csr[8] >> 8,
653: s->csr[9] & 0xff, s->csr[9] >> 8,
1.1.1.3 root 654: s->csr[10] & 0xff, s->csr[10] >> 8,
655: s->csr[11] & 0xff, s->csr[11] >> 8
1.1 root 656: };
657: int index = lnc_mchash(hdr->ether_dhost) >> 26;
658: return !!(ladr[index >> 3] & (1 << (index & 7)));
659: }
660: return 0;
661: }
662:
1.1.1.3 root 663: static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
1.1 root 664: {
665: while (idx < 1) idx += CSR_RCVRL(s);
666: return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
667: }
668:
669: static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
670: {
1.1.1.3 root 671: int64_t next_time = current_time +
672: muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
1.1.1.8 root 673: get_ticks_per_sec(), 33000000L);
1.1 root 674: if (next_time <= current_time)
675: next_time = current_time + 1;
676: return next_time;
677: }
678:
679: static void pcnet_poll(PCNetState *s);
680: static void pcnet_poll_timer(void *opaque);
681:
682: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
683: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
684: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
685:
686: static void pcnet_s_reset(PCNetState *s)
687: {
688: #ifdef PCNET_DEBUG
689: printf("pcnet_s_reset\n");
690: #endif
691:
692: s->rdra = 0;
693: s->tdra = 0;
694: s->rap = 0;
1.1.1.3 root 695:
1.1 root 696: s->bcr[BCR_BSBC] &= ~0x0080;
697:
698: s->csr[0] = 0x0004;
699: s->csr[3] = 0x0000;
700: s->csr[4] = 0x0115;
701: s->csr[5] = 0x0000;
702: s->csr[6] = 0x0000;
703: s->csr[8] = 0;
704: s->csr[9] = 0;
705: s->csr[10] = 0;
706: s->csr[11] = 0;
707: s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
708: s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
709: s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
710: s->csr[15] &= 0x21c4;
711: s->csr[72] = 1;
712: s->csr[74] = 1;
713: s->csr[76] = 1;
714: s->csr[78] = 1;
715: s->csr[80] = 0x1410;
716: s->csr[88] = 0x1003;
717: s->csr[89] = 0x0262;
718: s->csr[94] = 0x0000;
719: s->csr[100] = 0x0200;
720: s->csr[103] = 0x0105;
721: s->csr[103] = 0x0105;
722: s->csr[112] = 0x0000;
723: s->csr[114] = 0x0000;
724: s->csr[122] = 0x0000;
725: s->csr[124] = 0x0000;
726:
727: s->tx_busy = 0;
728: }
729:
730: static void pcnet_update_irq(PCNetState *s)
731: {
732: int isr = 0;
733: s->csr[0] &= ~0x0080;
1.1.1.3 root 734:
1.1 root 735: #if 1
736: if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
737: (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
738: (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
739: #else
740: if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
741: (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
742: (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
743: (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
744: (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
745: (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
746: (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
747: (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
748: (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
749: (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
750: (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
751: (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
752: #endif
753: {
1.1.1.3 root 754:
1.1 root 755: isr = CSR_INEA(s);
756: s->csr[0] |= 0x0080;
757: }
1.1.1.3 root 758:
1.1 root 759: if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
760: s->csr[4] &= ~0x0080;
761: s->csr[4] |= 0x0040;
762: s->csr[0] |= 0x0080;
763: isr = 1;
764: #ifdef PCNET_DEBUG
765: printf("pcnet user int\n");
766: #endif
767: }
768:
769: #if 1
1.1.1.3 root 770: if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
1.1 root 771: #else
772: if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
773: (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
774: #endif
775: {
776: isr = 1;
777: s->csr[0] |= 0x0080;
778: }
779:
780: if (isr != s->isr) {
781: #ifdef PCNET_DEBUG
782: printf("pcnet: INTA=%d\n", isr);
783: #endif
784: }
1.1.1.3 root 785: qemu_set_irq(s->irq, isr);
1.1.1.2 root 786: s->isr = isr;
1.1 root 787: }
788:
789: static void pcnet_init(PCNetState *s)
790: {
1.1.1.2 root 791: int rlen, tlen;
1.1.1.3 root 792: uint16_t padr[3], ladrf[4], mode;
1.1.1.2 root 793: uint32_t rdra, tdra;
794:
1.1 root 795: #ifdef PCNET_DEBUG
796: printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
797: #endif
1.1.1.3 root 798:
1.1 root 799: if (BCR_SSIZE32(s)) {
800: struct pcnet_initblk32 initblk;
1.1.1.2 root 801: s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
802: (uint8_t *)&initblk, sizeof(initblk), 0);
1.1.1.3 root 803: mode = le16_to_cpu(initblk.mode);
1.1.1.2 root 804: rlen = initblk.rlen >> 4;
805: tlen = initblk.tlen >> 4;
1.1.1.3 root 806: ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
807: ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
808: ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
809: ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
810: padr[0] = le16_to_cpu(initblk.padr[0]);
811: padr[1] = le16_to_cpu(initblk.padr[1]);
812: padr[2] = le16_to_cpu(initblk.padr[2]);
1.1.1.2 root 813: rdra = le32_to_cpu(initblk.rdra);
814: tdra = le32_to_cpu(initblk.tdra);
1.1 root 815: } else {
816: struct pcnet_initblk16 initblk;
1.1.1.2 root 817: s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
818: (uint8_t *)&initblk, sizeof(initblk), 0);
1.1.1.3 root 819: mode = le16_to_cpu(initblk.mode);
820: ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
821: ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
822: ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
823: ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
824: padr[0] = le16_to_cpu(initblk.padr[0]);
825: padr[1] = le16_to_cpu(initblk.padr[1]);
826: padr[2] = le16_to_cpu(initblk.padr[2]);
1.1.1.2 root 827: rdra = le32_to_cpu(initblk.rdra);
828: tdra = le32_to_cpu(initblk.tdra);
829: rlen = rdra >> 29;
830: tlen = tdra >> 29;
831: rdra &= 0x00ffffff;
832: tdra &= 0x00ffffff;
1.1 root 833: }
1.1.1.3 root 834:
1.1.1.2 root 835: #if defined(PCNET_DEBUG)
1.1.1.3 root 836: printf("rlen=%d tlen=%d\n", rlen, tlen);
1.1.1.2 root 837: #endif
1.1.1.3 root 838:
1.1.1.2 root 839: CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
840: CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
841: s->csr[ 6] = (tlen << 12) | (rlen << 8);
1.1.1.3 root 842: s->csr[15] = mode;
843: s->csr[ 8] = ladrf[0];
844: s->csr[ 9] = ladrf[1];
845: s->csr[10] = ladrf[2];
846: s->csr[11] = ladrf[3];
847: s->csr[12] = padr[0];
848: s->csr[13] = padr[1];
849: s->csr[14] = padr[2];
1.1.1.2 root 850: s->rdra = PHYSADDR(s, rdra);
851: s->tdra = PHYSADDR(s, tdra);
1.1 root 852:
853: CSR_RCVRC(s) = CSR_RCVRL(s);
854: CSR_XMTRC(s) = CSR_XMTRL(s);
855:
856: #ifdef PCNET_DEBUG
1.1.1.3 root 857: printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
1.1 root 858: BCR_SSIZE32(s),
859: s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
860: #endif
861:
1.1.1.3 root 862: s->csr[0] |= 0x0101;
1.1 root 863: s->csr[0] &= ~0x0004; /* clear STOP bit */
864: }
865:
866: static void pcnet_start(PCNetState *s)
867: {
868: #ifdef PCNET_DEBUG
869: printf("pcnet_start\n");
870: #endif
871:
872: if (!CSR_DTX(s))
873: s->csr[0] |= 0x0010; /* set TXON */
1.1.1.3 root 874:
1.1 root 875: if (!CSR_DRX(s))
876: s->csr[0] |= 0x0020; /* set RXON */
877:
878: s->csr[0] &= ~0x0004; /* clear STOP bit */
879: s->csr[0] |= 0x0002;
1.1.1.7 root 880: pcnet_poll_timer(s);
1.1 root 881: }
882:
883: static void pcnet_stop(PCNetState *s)
884: {
885: #ifdef PCNET_DEBUG
886: printf("pcnet_stop\n");
887: #endif
1.1.1.13! root 888: s->csr[0] &= ~0xffeb;
1.1 root 889: s->csr[0] |= 0x0014;
890: s->csr[4] &= ~0x02c2;
891: s->csr[5] &= ~0x0011;
892: pcnet_poll_timer(s);
893: }
894:
895: static void pcnet_rdte_poll(PCNetState *s)
896: {
897: s->csr[28] = s->csr[29] = 0;
898: if (s->rdra) {
899: int bad = 0;
900: #if 1
901: target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
902: target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
903: target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
904: #else
1.1.1.3 root 905: target_phys_addr_t crda = s->rdra +
1.1 root 906: (CSR_RCVRL(s) - CSR_RCVRC(s)) *
907: (BCR_SWSTYLE(s) ? 16 : 8 );
908: int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
1.1.1.3 root 909: target_phys_addr_t nrda = s->rdra +
1.1 root 910: (CSR_RCVRL(s) - nrdc) *
911: (BCR_SWSTYLE(s) ? 16 : 8 );
912: int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
1.1.1.3 root 913: target_phys_addr_t nnrd = s->rdra +
1.1 root 914: (CSR_RCVRL(s) - nnrc) *
915: (BCR_SWSTYLE(s) ? 16 : 8 );
916: #endif
917:
1.1.1.6 root 918: CHECK_RMD(crda, bad);
1.1 root 919: if (!bad) {
1.1.1.6 root 920: CHECK_RMD(nrda, bad);
1.1 root 921: if (bad || (nrda == crda)) nrda = 0;
1.1.1.6 root 922: CHECK_RMD(nnrd, bad);
1.1 root 923: if (bad || (nnrd == crda)) nnrd = 0;
924:
925: s->csr[28] = crda & 0xffff;
926: s->csr[29] = crda >> 16;
927: s->csr[26] = nrda & 0xffff;
928: s->csr[27] = nrda >> 16;
929: s->csr[36] = nnrd & 0xffff;
930: s->csr[37] = nnrd >> 16;
931: #ifdef PCNET_DEBUG
932: if (bad) {
1.1.1.4 root 933: printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
1.1.1.6 root 934: crda);
1.1 root 935: }
936: } else {
1.1.1.4 root 937: printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
1.1.1.6 root 938: crda);
1.1 root 939: #endif
940: }
941: }
1.1.1.3 root 942:
1.1 root 943: if (CSR_CRDA(s)) {
944: struct pcnet_RMD rmd;
945: RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
1.1.1.3 root 946: CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
947: CSR_CRST(s) = rmd.status;
1.1 root 948: #ifdef PCNET_DEBUG_RMD_X
1.1.1.3 root 949: printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
1.1 root 950: PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
1.1.1.3 root 951: rmd.buf_length, rmd.status, rmd.msg_length);
1.1 root 952: PRINT_RMD(&rmd);
953: #endif
954: } else {
955: CSR_CRBC(s) = CSR_CRST(s) = 0;
956: }
1.1.1.3 root 957:
1.1 root 958: if (CSR_NRDA(s)) {
959: struct pcnet_RMD rmd;
960: RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
1.1.1.3 root 961: CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
962: CSR_NRST(s) = rmd.status;
1.1 root 963: } else {
964: CSR_NRBC(s) = CSR_NRST(s) = 0;
965: }
966:
967: }
968:
969: static int pcnet_tdte_poll(PCNetState *s)
970: {
971: s->csr[34] = s->csr[35] = 0;
972: if (s->tdra) {
1.1.1.3 root 973: target_phys_addr_t cxda = s->tdra +
1.1 root 974: (CSR_XMTRL(s) - CSR_XMTRC(s)) *
1.1.1.3 root 975: (BCR_SWSTYLE(s) ? 16 : 8);
1.1 root 976: int bad = 0;
1.1.1.6 root 977: CHECK_TMD(cxda, bad);
1.1 root 978: if (!bad) {
979: if (CSR_CXDA(s) != cxda) {
980: s->csr[60] = s->csr[34];
981: s->csr[61] = s->csr[35];
982: s->csr[62] = CSR_CXBC(s);
983: s->csr[63] = CSR_CXST(s);
984: }
985: s->csr[34] = cxda & 0xffff;
986: s->csr[35] = cxda >> 16;
1.1.1.3 root 987: #ifdef PCNET_DEBUG_X
1.1.1.6 root 988: printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
1.1 root 989: #endif
990: }
991: }
992:
993: if (CSR_CXDA(s)) {
994: struct pcnet_TMD tmd;
995:
1.1.1.3 root 996: TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1.1 root 997:
1.1.1.3 root 998: CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
999: CSR_CXST(s) = tmd.status;
1.1 root 1000: } else {
1001: CSR_CXBC(s) = CSR_CXST(s) = 0;
1002: }
1.1.1.3 root 1003:
1.1 root 1004: return !!(CSR_CXST(s) & 0x8000);
1005: }
1006:
1.1.1.8 root 1007: int pcnet_can_receive(VLANClientState *nc)
1.1 root 1008: {
1.1.1.8 root 1009: PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1 root 1010: if (CSR_STOP(s) || CSR_SPND(s))
1011: return 0;
1.1.1.3 root 1012:
1.1 root 1013: return sizeof(s->buffer)-16;
1014: }
1015:
1016: #define MIN_BUF_SIZE 60
1017:
1.1.1.8 root 1018: ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_)
1.1 root 1019: {
1.1.1.8 root 1020: PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1 root 1021: int is_padr = 0, is_bcast = 0, is_ladr = 0;
1022: uint8_t buf1[60];
1.1.1.4 root 1023: int remaining;
1024: int crc_err = 0;
1.1.1.6 root 1025: int size = size_;
1.1 root 1026:
1.1.1.10 root 1027: if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
1028: (CSR_LOOP(s) && !s->looptest)) {
1.1.1.6 root 1029: return -1;
1.1.1.10 root 1030: }
1.1 root 1031: #ifdef PCNET_DEBUG
1032: printf("pcnet_receive size=%d\n", size);
1033: #endif
1034:
1035: /* if too small buffer, then expand it */
1036: if (size < MIN_BUF_SIZE) {
1037: memcpy(buf1, buf, size);
1038: memset(buf1 + size, 0, MIN_BUF_SIZE - size);
1039: buf = buf1;
1040: size = MIN_BUF_SIZE;
1041: }
1042:
1.1.1.3 root 1043: if (CSR_PROM(s)
1044: || (is_padr=padr_match(s, buf, size))
1.1 root 1045: || (is_bcast=padr_bcast(s, buf, size))
1046: || (is_ladr=ladr_match(s, buf, size))) {
1047:
1048: pcnet_rdte_poll(s);
1049:
1050: if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
1051: struct pcnet_RMD rmd;
1052: int rcvrc = CSR_RCVRC(s)-1,i;
1053: target_phys_addr_t nrda;
1054: for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
1055: if (rcvrc <= 1)
1056: rcvrc = CSR_RCVRL(s);
1057: nrda = s->rdra +
1058: (CSR_RCVRL(s) - rcvrc) *
1059: (BCR_SWSTYLE(s) ? 16 : 8 );
1.1.1.6 root 1060: RMDLOAD(&rmd, nrda);
1.1.1.3 root 1061: if (GET_FIELD(rmd.status, RMDS, OWN)) {
1.1 root 1062: #ifdef PCNET_DEBUG_RMD
1.1.1.3 root 1063: printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
1.1 root 1064: rcvrc, CSR_RCVRC(s));
1065: #endif
1066: CSR_RCVRC(s) = rcvrc;
1067: pcnet_rdte_poll(s);
1068: break;
1069: }
1070: }
1071: }
1072:
1073: if (!(CSR_CRST(s) & 0x8000)) {
1074: #ifdef PCNET_DEBUG_RMD
1075: printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
1076: #endif
1077: s->csr[0] |= 0x1000; /* Set MISS flag */
1078: CSR_MISSC(s)++;
1079: } else {
1.1.1.4 root 1080: uint8_t *src = s->buffer;
1.1 root 1081: target_phys_addr_t crda = CSR_CRDA(s);
1082: struct pcnet_RMD rmd;
1083: int pktcount = 0;
1084:
1.1.1.4 root 1085: if (!s->looptest) {
1086: memcpy(src, buf, size);
1087: /* no need to compute the CRC */
1088: src[size] = 0;
1089: src[size + 1] = 0;
1090: src[size + 2] = 0;
1091: src[size + 3] = 0;
1092: size += 4;
1093: } else if (s->looptest == PCNET_LOOPTEST_CRC ||
1094: !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
1.1 root 1095: uint32_t fcs = ~0;
1096: uint8_t *p = src;
1097:
1.1.1.4 root 1098: while (p != &src[size])
1099: CRC(fcs, *p++);
1100: *(uint32_t *)p = htonl(fcs);
1101: size += 4;
1102: } else {
1103: uint32_t fcs = ~0;
1104: uint8_t *p = src;
1.1.1.3 root 1105:
1.1.1.4 root 1106: while (p != &src[size-4])
1.1 root 1107: CRC(fcs, *p++);
1.1.1.4 root 1108: crc_err = (*(uint32_t *)p != htonl(fcs));
1109: }
1.1 root 1110:
1111: #ifdef PCNET_DEBUG_MATCH
1112: PRINT_PKTHDR(buf);
1113: #endif
1114:
1115: RMDLOAD(&rmd, PHYSADDR(s,crda));
1116: /*if (!CSR_LAPPEN(s))*/
1.1.1.3 root 1117: SET_FIELD(&rmd.status, RMDS, STP, 1);
1.1 root 1118:
1119: #define PCNET_RECV_STORE() do { \
1.1.1.4 root 1120: int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
1.1.1.3 root 1121: target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \
1122: s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
1.1.1.4 root 1123: src += count; remaining -= count; \
1.1.1.3 root 1124: SET_FIELD(&rmd.status, RMDS, OWN, 0); \
1.1 root 1125: RMDSTORE(&rmd, PHYSADDR(s,crda)); \
1126: pktcount++; \
1127: } while (0)
1128:
1.1.1.4 root 1129: remaining = size;
1.1 root 1130: PCNET_RECV_STORE();
1.1.1.4 root 1131: if ((remaining > 0) && CSR_NRDA(s)) {
1.1 root 1132: target_phys_addr_t nrda = CSR_NRDA(s);
1.1.1.4 root 1133: #ifdef PCNET_DEBUG_RMD
1134: PRINT_RMD(&rmd);
1135: #endif
1.1 root 1136: RMDLOAD(&rmd, PHYSADDR(s,nrda));
1.1.1.3 root 1137: if (GET_FIELD(rmd.status, RMDS, OWN)) {
1.1 root 1138: crda = nrda;
1139: PCNET_RECV_STORE();
1.1.1.4 root 1140: #ifdef PCNET_DEBUG_RMD
1141: PRINT_RMD(&rmd);
1142: #endif
1143: if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
1.1 root 1144: RMDLOAD(&rmd, PHYSADDR(s,nrda));
1.1.1.3 root 1145: if (GET_FIELD(rmd.status, RMDS, OWN)) {
1.1 root 1146: crda = nrda;
1147: PCNET_RECV_STORE();
1148: }
1149: }
1.1.1.3 root 1150: }
1.1 root 1151: }
1152:
1153: #undef PCNET_RECV_STORE
1154:
1155: RMDLOAD(&rmd, PHYSADDR(s,crda));
1.1.1.4 root 1156: if (remaining == 0) {
1157: SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
1.1.1.3 root 1158: SET_FIELD(&rmd.status, RMDS, ENP, 1);
1159: SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
1160: SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
1161: SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
1.1.1.4 root 1162: if (crc_err) {
1163: SET_FIELD(&rmd.status, RMDS, CRC, 1);
1164: SET_FIELD(&rmd.status, RMDS, ERR, 1);
1165: }
1.1 root 1166: } else {
1.1.1.3 root 1167: SET_FIELD(&rmd.status, RMDS, OFLO, 1);
1168: SET_FIELD(&rmd.status, RMDS, BUFF, 1);
1169: SET_FIELD(&rmd.status, RMDS, ERR, 1);
1.1 root 1170: }
1171: RMDSTORE(&rmd, PHYSADDR(s,crda));
1172: s->csr[0] |= 0x0400;
1173:
1174: #ifdef PCNET_DEBUG
1.1.1.3 root 1175: printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
1.1 root 1176: CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
1177: #endif
1178: #ifdef PCNET_DEBUG_RMD
1179: PRINT_RMD(&rmd);
1.1.1.3 root 1180: #endif
1.1 root 1181:
1182: while (pktcount--) {
1183: if (CSR_RCVRC(s) <= 1)
1184: CSR_RCVRC(s) = CSR_RCVRL(s);
1185: else
1.1.1.3 root 1186: CSR_RCVRC(s)--;
1.1 root 1187: }
1.1.1.3 root 1188:
1.1 root 1189: pcnet_rdte_poll(s);
1190:
1.1.1.3 root 1191: }
1.1 root 1192: }
1193:
1194: pcnet_poll(s);
1.1.1.3 root 1195: pcnet_update_irq(s);
1.1.1.6 root 1196:
1197: return size_;
1.1 root 1198: }
1199:
1.1.1.12 root 1200: void pcnet_set_link_status(VLANClientState *nc)
1201: {
1202: PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
1203:
1204: d->lnkst = nc->link_down ? 0 : 0x40;
1205: }
1206:
1.1 root 1207: static void pcnet_transmit(PCNetState *s)
1208: {
1209: target_phys_addr_t xmit_cxda = 0;
1210: int count = CSR_XMTRL(s)-1;
1.1.1.4 root 1211: int add_crc = 0;
1212:
1.1 root 1213: s->xmit_pos = -1;
1.1.1.3 root 1214:
1.1 root 1215: if (!CSR_TXON(s)) {
1216: s->csr[0] &= ~0x0008;
1217: return;
1218: }
1219:
1220: s->tx_busy = 1;
1221:
1222: txagain:
1223: if (pcnet_tdte_poll(s)) {
1224: struct pcnet_TMD tmd;
1225:
1.1.1.3 root 1226: TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1.1 root 1227:
1228: #ifdef PCNET_DEBUG_TMD
1229: printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
1230: PRINT_TMD(&tmd);
1231: #endif
1.1.1.3 root 1232: if (GET_FIELD(tmd.status, TMDS, STP)) {
1233: s->xmit_pos = 0;
1.1 root 1234: xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
1.1.1.4 root 1235: if (BCR_SWSTYLE(s) != 1)
1236: add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
1.1 root 1237: }
1.1.1.13! root 1238: if (s->lnkst == 0 &&
! 1239: (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
! 1240: SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
! 1241: SET_FIELD(&tmd.status, TMDS, ERR, 1);
! 1242: SET_FIELD(&tmd.status, TMDS, OWN, 0);
! 1243: s->csr[0] |= 0xa000; /* ERR | CERR */
! 1244: s->xmit_pos = -1;
! 1245: goto txdone;
! 1246: }
1.1.1.4 root 1247: if (!GET_FIELD(tmd.status, TMDS, ENP)) {
1248: int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
1249: s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
1250: s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
1251: s->xmit_pos += bcnt;
1252: } else if (s->xmit_pos >= 0) {
1.1.1.3 root 1253: int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
1254: s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
1255: s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
1256: s->xmit_pos += bcnt;
1.1 root 1257: #ifdef PCNET_DEBUG
1258: printf("pcnet_transmit size=%d\n", s->xmit_pos);
1.1.1.3 root 1259: #endif
1.1.1.4 root 1260: if (CSR_LOOP(s)) {
1261: if (BCR_SWSTYLE(s) == 1)
1262: add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
1263: s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
1.1.1.8 root 1264: pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos);
1.1.1.4 root 1265: s->looptest = 0;
1266: } else
1.1.1.8 root 1267: if (s->nic)
1268: qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos);
1.1 root 1269:
1270: s->csr[0] &= ~0x0008; /* clear TDMD */
1271: s->csr[4] |= 0x0004; /* set TXSTRT */
1272: s->xmit_pos = -1;
1273: }
1274:
1.1.1.13! root 1275: txdone:
1.1.1.3 root 1276: SET_FIELD(&tmd.status, TMDS, OWN, 0);
1.1 root 1277: TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1.1.1.3 root 1278: if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
1.1 root 1279: s->csr[0] |= 0x0200; /* set TINT */
1280:
1281: if (CSR_XMTRC(s)<=1)
1282: CSR_XMTRC(s) = CSR_XMTRL(s);
1283: else
1284: CSR_XMTRC(s)--;
1285: if (count--)
1286: goto txagain;
1287:
1.1.1.3 root 1288: } else
1.1 root 1289: if (s->xmit_pos >= 0) {
1290: struct pcnet_TMD tmd;
1.1.1.6 root 1291: TMDLOAD(&tmd, xmit_cxda);
1.1.1.3 root 1292: SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
1293: SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
1294: SET_FIELD(&tmd.status, TMDS, ERR, 1);
1295: SET_FIELD(&tmd.status, TMDS, OWN, 0);
1.1.1.6 root 1296: TMDSTORE(&tmd, xmit_cxda);
1.1 root 1297: s->csr[0] |= 0x0200; /* set TINT */
1298: if (!CSR_DXSUFLO(s)) {
1299: s->csr[0] &= ~0x0010;
1300: } else
1301: if (count--)
1302: goto txagain;
1303: }
1304:
1305: s->tx_busy = 0;
1306: }
1307:
1308: static void pcnet_poll(PCNetState *s)
1309: {
1310: if (CSR_RXON(s)) {
1311: pcnet_rdte_poll(s);
1312: }
1313:
1.1.1.3 root 1314: if (CSR_TDMD(s) ||
1.1 root 1315: (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
1316: {
1317: /* prevent recursion */
1318: if (s->tx_busy)
1319: return;
1320:
1321: pcnet_transmit(s);
1322: }
1323: }
1324:
1325: static void pcnet_poll_timer(void *opaque)
1326: {
1327: PCNetState *s = opaque;
1328:
1329: qemu_del_timer(s->poll_timer);
1330:
1331: if (CSR_TDMD(s)) {
1332: pcnet_transmit(s);
1333: }
1334:
1.1.1.3 root 1335: pcnet_update_irq(s);
1.1 root 1336:
1337: if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
1.1.1.11 root 1338: uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
1.1 root 1339: if (!s->timer || !now)
1340: s->timer = now;
1341: else {
1342: uint64_t t = now - s->timer + CSR_POLL(s);
1343: if (t > 0xffffLL) {
1344: pcnet_poll(s);
1345: CSR_POLL(s) = CSR_PINT(s);
1346: } else
1347: CSR_POLL(s) = t;
1348: }
1.1.1.3 root 1349: qemu_mod_timer(s->poll_timer,
1.1.1.11 root 1350: pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
1.1 root 1351: }
1352: }
1353:
1354:
1355: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
1356: {
1357: uint16_t val = new_value;
1358: #ifdef PCNET_DEBUG_CSR
1359: printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
1360: #endif
1361: switch (rap) {
1362: case 0:
1363: s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
1364:
1365: s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
1366:
1367: val = (val & 0x007f) | (s->csr[0] & 0x7f00);
1368:
1369: /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
1370: if ((val&7) == 7)
1371: val &= ~3;
1372:
1373: if (!CSR_STOP(s) && (val & 4))
1374: pcnet_stop(s);
1375:
1376: if (!CSR_INIT(s) && (val & 1))
1377: pcnet_init(s);
1378:
1379: if (!CSR_STRT(s) && (val & 2))
1380: pcnet_start(s);
1381:
1.1.1.3 root 1382: if (CSR_TDMD(s))
1.1 root 1383: pcnet_transmit(s);
1384:
1385: return;
1386: case 1:
1387: case 2:
1388: case 8:
1389: case 9:
1390: case 10:
1391: case 11:
1392: case 12:
1393: case 13:
1394: case 14:
1395: case 15:
1396: case 18: /* CRBAL */
1397: case 19: /* CRBAU */
1398: case 20: /* CXBAL */
1399: case 21: /* CXBAU */
1400: case 22: /* NRBAU */
1401: case 23: /* NRBAU */
1402: case 24:
1403: case 25:
1404: case 26:
1405: case 27:
1406: case 28:
1407: case 29:
1408: case 30:
1409: case 31:
1410: case 32:
1411: case 33:
1412: case 34:
1413: case 35:
1414: case 36:
1415: case 37:
1416: case 38:
1417: case 39:
1418: case 40: /* CRBC */
1419: case 41:
1420: case 42: /* CXBC */
1421: case 43:
1422: case 44:
1423: case 45:
1424: case 46: /* POLL */
1425: case 47: /* POLLINT */
1426: case 72:
1427: case 74:
1428: case 76: /* RCVRL */
1429: case 78: /* XMTRL */
1430: case 112:
1431: if (CSR_STOP(s) || CSR_SPND(s))
1432: break;
1433: return;
1434: case 3:
1435: break;
1436: case 4:
1.1.1.3 root 1437: s->csr[4] &= ~(val & 0x026a);
1.1 root 1438: val &= ~0x026a; val |= s->csr[4] & 0x026a;
1439: break;
1440: case 5:
1.1.1.3 root 1441: s->csr[5] &= ~(val & 0x0a90);
1.1 root 1442: val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
1443: break;
1444: case 16:
1445: pcnet_csr_writew(s,1,val);
1446: return;
1447: case 17:
1448: pcnet_csr_writew(s,2,val);
1449: return;
1450: case 58:
1451: pcnet_bcr_writew(s,BCR_SWS,val);
1452: break;
1453: default:
1454: return;
1455: }
1456: s->csr[rap] = val;
1457: }
1458:
1459: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
1460: {
1461: uint32_t val;
1462: switch (rap) {
1463: case 0:
1464: pcnet_update_irq(s);
1465: val = s->csr[0];
1466: val |= (val & 0x7800) ? 0x8000 : 0;
1467: break;
1468: case 16:
1469: return pcnet_csr_readw(s,1);
1470: case 17:
1471: return pcnet_csr_readw(s,2);
1472: case 58:
1473: return pcnet_bcr_readw(s,BCR_SWS);
1474: case 88:
1475: val = s->csr[89];
1476: val <<= 16;
1477: val |= s->csr[88];
1478: break;
1479: default:
1480: val = s->csr[rap];
1481: }
1482: #ifdef PCNET_DEBUG_CSR
1483: printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
1484: #endif
1485: return val;
1486: }
1487:
1488: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
1489: {
1490: rap &= 127;
1491: #ifdef PCNET_DEBUG_BCR
1492: printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
1493: #endif
1494: switch (rap) {
1495: case BCR_SWS:
1496: if (!(CSR_STOP(s) || CSR_SPND(s)))
1497: return;
1498: val &= ~0x0300;
1499: switch (val & 0x00ff) {
1500: case 0:
1501: val |= 0x0200;
1502: break;
1503: case 1:
1504: val |= 0x0100;
1505: break;
1506: case 2:
1507: case 3:
1508: val |= 0x0300;
1509: break;
1510: default:
1511: printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
1512: val = 0x0200;
1513: break;
1514: }
1515: #ifdef PCNET_DEBUG
1516: printf("BCR_SWS=0x%04x\n", val);
1517: #endif
1.1.1.13! root 1518: /* fall through */
1.1 root 1519: case BCR_LNKST:
1520: case BCR_LED1:
1521: case BCR_LED2:
1522: case BCR_LED3:
1523: case BCR_MC:
1524: case BCR_FDC:
1525: case BCR_BSBC:
1526: case BCR_EECAS:
1527: case BCR_PLAT:
1528: s->bcr[rap] = val;
1529: break;
1530: default:
1531: break;
1532: }
1533: }
1534:
1.1.1.10 root 1535: uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
1.1 root 1536: {
1537: uint32_t val;
1538: rap &= 127;
1539: switch (rap) {
1540: case BCR_LNKST:
1541: case BCR_LED1:
1542: case BCR_LED2:
1543: case BCR_LED3:
1544: val = s->bcr[rap] & ~0x8000;
1545: val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
1546: break;
1547: default:
1548: val = rap < 32 ? s->bcr[rap] : 0;
1549: break;
1550: }
1551: #ifdef PCNET_DEBUG_BCR
1552: printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
1553: #endif
1554: return val;
1555: }
1556:
1.1.1.8 root 1557: void pcnet_h_reset(void *opaque)
1.1 root 1558: {
1.1.1.2 root 1559: PCNetState *s = opaque;
1.1 root 1560:
1561: s->bcr[BCR_MSRDA] = 0x0005;
1562: s->bcr[BCR_MSWRA] = 0x0005;
1563: s->bcr[BCR_MC ] = 0x0002;
1564: s->bcr[BCR_LNKST] = 0x00c0;
1565: s->bcr[BCR_LED1 ] = 0x0084;
1566: s->bcr[BCR_LED2 ] = 0x0088;
1567: s->bcr[BCR_LED3 ] = 0x0090;
1568: s->bcr[BCR_FDC ] = 0x0000;
1569: s->bcr[BCR_BSBC ] = 0x9001;
1570: s->bcr[BCR_EECAS] = 0x0002;
1571: s->bcr[BCR_SWS ] = 0x0200;
1572: s->bcr[BCR_PLAT ] = 0xff06;
1573:
1574: pcnet_s_reset(s);
1.1.1.8 root 1575: pcnet_update_irq(s);
1576: pcnet_poll_timer(s);
1.1 root 1577: }
1578:
1.1.1.8 root 1579: void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
1.1 root 1580: {
1581: PCNetState *s = opaque;
1582: pcnet_poll_timer(s);
1583: #ifdef PCNET_DEBUG_IO
1584: printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
1585: #endif
1586: if (!BCR_DWIO(s)) {
1587: switch (addr & 0x0f) {
1588: case 0x00: /* RDP */
1589: pcnet_csr_writew(s, s->rap, val);
1590: break;
1591: case 0x02:
1592: s->rap = val & 0x7f;
1593: break;
1594: case 0x06:
1595: pcnet_bcr_writew(s, s->rap, val);
1596: break;
1597: }
1598: }
1599: pcnet_update_irq(s);
1600: }
1601:
1.1.1.8 root 1602: uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
1.1 root 1603: {
1604: PCNetState *s = opaque;
1605: uint32_t val = -1;
1606: pcnet_poll_timer(s);
1607: if (!BCR_DWIO(s)) {
1608: switch (addr & 0x0f) {
1609: case 0x00: /* RDP */
1610: val = pcnet_csr_readw(s, s->rap);
1611: break;
1612: case 0x02:
1613: val = s->rap;
1614: break;
1615: case 0x04:
1616: pcnet_s_reset(s);
1617: val = 0;
1618: break;
1619: case 0x06:
1620: val = pcnet_bcr_readw(s, s->rap);
1621: break;
1622: }
1623: }
1624: pcnet_update_irq(s);
1625: #ifdef PCNET_DEBUG_IO
1626: printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
1627: #endif
1628: return val;
1629: }
1630:
1.1.1.10 root 1631: void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
1.1 root 1632: {
1633: PCNetState *s = opaque;
1634: pcnet_poll_timer(s);
1635: #ifdef PCNET_DEBUG_IO
1636: printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
1637: #endif
1638: if (BCR_DWIO(s)) {
1639: switch (addr & 0x0f) {
1640: case 0x00: /* RDP */
1641: pcnet_csr_writew(s, s->rap, val & 0xffff);
1642: break;
1643: case 0x04:
1644: s->rap = val & 0x7f;
1645: break;
1646: case 0x0c:
1647: pcnet_bcr_writew(s, s->rap, val & 0xffff);
1648: break;
1649: }
1650: } else
1651: if ((addr & 0x0f) == 0) {
1652: /* switch device to dword i/o mode */
1653: pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
1654: #ifdef PCNET_DEBUG_IO
1655: printf("device switched into dword i/o mode\n");
1.1.1.3 root 1656: #endif
1.1 root 1657: }
1658: pcnet_update_irq(s);
1659: }
1660:
1.1.1.10 root 1661: uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
1.1 root 1662: {
1663: PCNetState *s = opaque;
1664: uint32_t val = -1;
1665: pcnet_poll_timer(s);
1.1.1.3 root 1666: if (BCR_DWIO(s)) {
1.1 root 1667: switch (addr & 0x0f) {
1668: case 0x00: /* RDP */
1669: val = pcnet_csr_readw(s, s->rap);
1670: break;
1671: case 0x04:
1672: val = s->rap;
1673: break;
1674: case 0x08:
1675: pcnet_s_reset(s);
1676: val = 0;
1677: break;
1678: case 0x0c:
1679: val = pcnet_bcr_readw(s, s->rap);
1680: break;
1681: }
1682: }
1683: pcnet_update_irq(s);
1684: #ifdef PCNET_DEBUG_IO
1685: printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
1686: #endif
1687: return val;
1688: }
1689:
1.1.1.8 root 1690: static bool is_version_2(void *opaque, int version_id)
1.1.1.2 root 1691: {
1.1.1.8 root 1692: return version_id == 2;
1.1.1.2 root 1693: }
1694:
1.1.1.8 root 1695: const VMStateDescription vmstate_pcnet = {
1696: .name = "pcnet",
1697: .version_id = 3,
1698: .minimum_version_id = 2,
1699: .minimum_version_id_old = 2,
1700: .fields = (VMStateField []) {
1701: VMSTATE_INT32(rap, PCNetState),
1702: VMSTATE_INT32(isr, PCNetState),
1703: VMSTATE_INT32(lnkst, PCNetState),
1704: VMSTATE_UINT32(rdra, PCNetState),
1705: VMSTATE_UINT32(tdra, PCNetState),
1706: VMSTATE_BUFFER(prom, PCNetState),
1707: VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
1708: VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
1709: VMSTATE_UINT64(timer, PCNetState),
1710: VMSTATE_INT32(xmit_pos, PCNetState),
1711: VMSTATE_BUFFER(buffer, PCNetState),
1712: VMSTATE_UNUSED_TEST(is_version_2, 4),
1713: VMSTATE_INT32(tx_busy, PCNetState),
1714: VMSTATE_TIMER(poll_timer, PCNetState),
1715: VMSTATE_END_OF_LIST()
1716: }
1717: };
1.1.1.2 root 1718:
1.1.1.8 root 1719: void pcnet_common_cleanup(PCNetState *d)
1.1.1.5 root 1720: {
1.1.1.8 root 1721: d->nic = NULL;
1.1.1.5 root 1722: }
1723:
1.1.1.8 root 1724: int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
1.1.1.2 root 1725: {
1.1.1.11 root 1726: int i;
1727: uint16_t checksum;
1728:
1729: s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
1.1.1.2 root 1730:
1.1.1.8 root 1731: qemu_macaddr_default_if_unset(&s->conf.macaddr);
1.1.1.13! root 1732: s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
1.1.1.8 root 1733: qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
1.1.1.5 root 1734:
1.1.1.10 root 1735: add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
1.1.1.5 root 1736:
1.1.1.11 root 1737: /* Initialize the PROM */
1738:
1739: /*
1740: Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
1741: page 95
1742: */
1743: memcpy(s->prom, s->conf.macaddr.a, 6);
1744: /* Reserved Location: must be 00h */
1745: s->prom[6] = s->prom[7] = 0x00;
1746: /* Reserved Location: must be 00h */
1747: s->prom[8] = 0x00;
1748: /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
1749: s->prom[9] = 0x11;
1750: /* User programmable space, init with 0 */
1751: s->prom[10] = s->prom[11] = 0x00;
1752: /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
1753: and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
1754: s->prom[12] = s->prom[13] = 0x00;
1755: /* Must be ASCII W (57h) if compatibility to AMD
1756: driver software is desired */
1757: s->prom[14] = s->prom[15] = 0x57;
1758:
1759: for (i = 0, checksum = 0; i < 16; i++) {
1760: checksum += s->prom[i];
1761: }
1762: *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
1763:
1.1.1.13! root 1764: s->lnkst = 0x40; /* initial link state: up */
! 1765:
1.1.1.5 root 1766: return 0;
1767: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.