|
|
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 root 80: #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
81: #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
82: #define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
83:
84: #define CSR_CRBC(S) ((S)->csr[40])
85: #define CSR_CRST(S) ((S)->csr[41])
86: #define CSR_CXBC(S) ((S)->csr[42])
87: #define CSR_CXST(S) ((S)->csr[43])
88: #define CSR_NRBC(S) ((S)->csr[44])
89: #define CSR_NRST(S) ((S)->csr[45])
90: #define CSR_POLL(S) ((S)->csr[46])
91: #define CSR_PINT(S) ((S)->csr[47])
92: #define CSR_RCVRC(S) ((S)->csr[72])
93: #define CSR_XMTRC(S) ((S)->csr[74])
94: #define CSR_RCVRL(S) ((S)->csr[76])
95: #define CSR_XMTRL(S) ((S)->csr[78])
96: #define CSR_MISSC(S) ((S)->csr[112])
97:
1.1.1.11 root 98: #define CSR_IADR(S) ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
99: #define CSR_CRBA(S) ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
100: #define CSR_CXBA(S) ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
101: #define CSR_NRBA(S) ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
102: #define CSR_BADR(S) ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
103: #define CSR_NRDA(S) ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
104: #define CSR_CRDA(S) ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
105: #define CSR_BADX(S) ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
106: #define CSR_NXDA(S) ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
107: #define CSR_CXDA(S) ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
108: #define CSR_NNRD(S) ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
109: #define CSR_NNXD(S) ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
110: #define CSR_PXDA(S) ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
111: #define CSR_NXBA(S) ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
1.1 root 112:
113: #define PHYSADDR(S,A) \
1.1.1.11 root 114: (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
1.1 root 115:
116: struct pcnet_initblk16 {
117: uint16_t mode;
1.1.1.2 root 118: uint16_t padr[3];
119: uint16_t ladrf[4];
120: uint32_t rdra;
121: uint32_t tdra;
1.1 root 122: };
123:
124: struct pcnet_initblk32 {
125: uint16_t mode;
1.1.1.2 root 126: uint8_t rlen;
127: uint8_t tlen;
128: uint16_t padr[3];
1.1 root 129: uint16_t _res;
1.1.1.2 root 130: uint16_t ladrf[4];
1.1 root 131: uint32_t rdra;
132: uint32_t tdra;
133: };
134:
135: struct pcnet_TMD {
1.1.1.3 root 136: uint32_t tbadr;
137: int16_t length;
138: int16_t status;
139: uint32_t misc;
140: uint32_t res;
1.1 root 141: };
142:
1.1.1.3 root 143: #define TMDL_BCNT_MASK 0x0fff
144: #define TMDL_BCNT_SH 0
145: #define TMDL_ONES_MASK 0xf000
146: #define TMDL_ONES_SH 12
147:
148: #define TMDS_BPE_MASK 0x0080
149: #define TMDS_BPE_SH 7
150: #define TMDS_ENP_MASK 0x0100
151: #define TMDS_ENP_SH 8
152: #define TMDS_STP_MASK 0x0200
153: #define TMDS_STP_SH 9
154: #define TMDS_DEF_MASK 0x0400
155: #define TMDS_DEF_SH 10
156: #define TMDS_ONE_MASK 0x0800
157: #define TMDS_ONE_SH 11
158: #define TMDS_LTINT_MASK 0x1000
159: #define TMDS_LTINT_SH 12
160: #define TMDS_NOFCS_MASK 0x2000
161: #define TMDS_NOFCS_SH 13
1.1.1.4 root 162: #define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
163: #define TMDS_ADDFCS_SH TMDS_NOFCS_SH
1.1.1.3 root 164: #define TMDS_ERR_MASK 0x4000
165: #define TMDS_ERR_SH 14
166: #define TMDS_OWN_MASK 0x8000
167: #define TMDS_OWN_SH 15
168:
169: #define TMDM_TRC_MASK 0x0000000f
170: #define TMDM_TRC_SH 0
171: #define TMDM_TDR_MASK 0x03ff0000
172: #define TMDM_TDR_SH 16
173: #define TMDM_RTRY_MASK 0x04000000
174: #define TMDM_RTRY_SH 26
175: #define TMDM_LCAR_MASK 0x08000000
176: #define TMDM_LCAR_SH 27
177: #define TMDM_LCOL_MASK 0x10000000
178: #define TMDM_LCOL_SH 28
179: #define TMDM_EXDEF_MASK 0x20000000
180: #define TMDM_EXDEF_SH 29
181: #define TMDM_UFLO_MASK 0x40000000
182: #define TMDM_UFLO_SH 30
183: #define TMDM_BUFF_MASK 0x80000000
184: #define TMDM_BUFF_SH 31
185:
1.1 root 186: struct pcnet_RMD {
1.1.1.3 root 187: uint32_t rbadr;
188: int16_t buf_length;
189: int16_t status;
190: uint32_t msg_length;
191: uint32_t res;
1.1 root 192: };
193:
1.1.1.3 root 194: #define RMDL_BCNT_MASK 0x0fff
195: #define RMDL_BCNT_SH 0
196: #define RMDL_ONES_MASK 0xf000
197: #define RMDL_ONES_SH 12
198:
199: #define RMDS_BAM_MASK 0x0010
200: #define RMDS_BAM_SH 4
201: #define RMDS_LFAM_MASK 0x0020
202: #define RMDS_LFAM_SH 5
203: #define RMDS_PAM_MASK 0x0040
204: #define RMDS_PAM_SH 6
205: #define RMDS_BPE_MASK 0x0080
206: #define RMDS_BPE_SH 7
207: #define RMDS_ENP_MASK 0x0100
208: #define RMDS_ENP_SH 8
209: #define RMDS_STP_MASK 0x0200
210: #define RMDS_STP_SH 9
211: #define RMDS_BUFF_MASK 0x0400
212: #define RMDS_BUFF_SH 10
213: #define RMDS_CRC_MASK 0x0800
214: #define RMDS_CRC_SH 11
215: #define RMDS_OFLO_MASK 0x1000
216: #define RMDS_OFLO_SH 12
217: #define RMDS_FRAM_MASK 0x2000
218: #define RMDS_FRAM_SH 13
219: #define RMDS_ERR_MASK 0x4000
220: #define RMDS_ERR_SH 14
221: #define RMDS_OWN_MASK 0x8000
222: #define RMDS_OWN_SH 15
223:
224: #define RMDM_MCNT_MASK 0x00000fff
225: #define RMDM_MCNT_SH 0
226: #define RMDM_ZEROS_MASK 0x0000f000
227: #define RMDM_ZEROS_SH 12
228: #define RMDM_RPC_MASK 0x00ff0000
229: #define RMDM_RPC_SH 16
230: #define RMDM_RCC_MASK 0xff000000
231: #define RMDM_RCC_SH 24
232:
233: #define SET_FIELD(regp, name, field, value) \
234: (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
235: | ((value) << name ## _ ## field ## _SH))
236:
237: #define GET_FIELD(reg, name, field) \
238: (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
1.1 root 239:
1.1.1.3 root 240: #define PRINT_TMD(T) printf( \
241: "TMD0 : TBADR=0x%08x\n" \
1.1 root 242: "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
243: "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
244: " BPE=%d, BCNT=%d\n" \
245: "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
246: "LCA=%d, RTR=%d,\n" \
247: " TDR=%d, TRC=%d\n", \
1.1.1.3 root 248: (T)->tbadr, \
249: GET_FIELD((T)->status, TMDS, OWN), \
250: GET_FIELD((T)->status, TMDS, ERR), \
251: GET_FIELD((T)->status, TMDS, NOFCS), \
252: GET_FIELD((T)->status, TMDS, LTINT), \
253: GET_FIELD((T)->status, TMDS, ONE), \
254: GET_FIELD((T)->status, TMDS, DEF), \
255: GET_FIELD((T)->status, TMDS, STP), \
256: GET_FIELD((T)->status, TMDS, ENP), \
257: GET_FIELD((T)->status, TMDS, BPE), \
258: 4096-GET_FIELD((T)->length, TMDL, BCNT), \
259: GET_FIELD((T)->misc, TMDM, BUFF), \
260: GET_FIELD((T)->misc, TMDM, UFLO), \
261: GET_FIELD((T)->misc, TMDM, EXDEF), \
262: GET_FIELD((T)->misc, TMDM, LCOL), \
263: GET_FIELD((T)->misc, TMDM, LCAR), \
264: GET_FIELD((T)->misc, TMDM, RTRY), \
265: GET_FIELD((T)->misc, TMDM, TDR), \
266: GET_FIELD((T)->misc, TMDM, TRC))
1.1 root 267:
1.1.1.3 root 268: #define PRINT_RMD(R) printf( \
269: "RMD0 : RBADR=0x%08x\n" \
1.1 root 270: "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
271: "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
1.1.1.3 root 272: "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
1.1 root 273: "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
1.1.1.3 root 274: (R)->rbadr, \
275: GET_FIELD((R)->status, RMDS, OWN), \
276: GET_FIELD((R)->status, RMDS, ERR), \
277: GET_FIELD((R)->status, RMDS, FRAM), \
278: GET_FIELD((R)->status, RMDS, OFLO), \
279: GET_FIELD((R)->status, RMDS, CRC), \
280: GET_FIELD((R)->status, RMDS, BUFF), \
281: GET_FIELD((R)->status, RMDS, STP), \
282: GET_FIELD((R)->status, RMDS, ENP), \
283: GET_FIELD((R)->status, RMDS, BPE), \
284: GET_FIELD((R)->status, RMDS, PAM), \
285: GET_FIELD((R)->status, RMDS, LFAM), \
286: GET_FIELD((R)->status, RMDS, BAM), \
287: GET_FIELD((R)->buf_length, RMDL, ONES), \
288: 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \
289: GET_FIELD((R)->msg_length, RMDM, RCC), \
290: GET_FIELD((R)->msg_length, RMDM, RPC), \
291: GET_FIELD((R)->msg_length, RMDM, MCNT), \
292: GET_FIELD((R)->msg_length, RMDM, ZEROS))
1.1 root 293:
1.1.1.3 root 294: static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
1.1.1.2 root 295: target_phys_addr_t addr)
1.1 root 296: {
1.1.1.3 root 297: if (!BCR_SSIZE32(s)) {
298: struct {
299: uint32_t tbadr;
300: int16_t length;
301: int16_t status;
302: } xda;
303: s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
304: tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
305: tmd->length = le16_to_cpu(xda.length);
306: tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
307: tmd->misc = le16_to_cpu(xda.status) << 16;
308: tmd->res = 0;
1.1.1.2 root 309: } else {
1.1.1.3 root 310: s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
311: le32_to_cpus(&tmd->tbadr);
312: le16_to_cpus((uint16_t *)&tmd->length);
313: le16_to_cpus((uint16_t *)&tmd->status);
314: le32_to_cpus(&tmd->misc);
315: le32_to_cpus(&tmd->res);
316: if (BCR_SWSTYLE(s) == 3) {
317: uint32_t tmp = tmd->tbadr;
318: tmd->tbadr = tmd->misc;
319: tmd->misc = tmp;
1.1.1.2 root 320: }
1.1 root 321: }
322: }
323:
1.1.1.3 root 324: static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
1.1.1.2 root 325: target_phys_addr_t addr)
1.1 root 326: {
1.1.1.3 root 327: if (!BCR_SSIZE32(s)) {
328: struct {
329: uint32_t tbadr;
330: int16_t length;
331: int16_t status;
332: } xda;
333: xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
334: ((tmd->status & 0xff00) << 16));
335: xda.length = cpu_to_le16(tmd->length);
336: xda.status = cpu_to_le16(tmd->misc >> 16);
337: s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
1.1.1.2 root 338: } else {
1.1.1.3 root 339: struct {
340: uint32_t tbadr;
341: int16_t length;
342: int16_t status;
343: uint32_t misc;
344: uint32_t res;
345: } xda;
346: xda.tbadr = cpu_to_le32(tmd->tbadr);
347: xda.length = cpu_to_le16(tmd->length);
348: xda.status = cpu_to_le16(tmd->status);
349: xda.misc = cpu_to_le32(tmd->misc);
350: xda.res = cpu_to_le32(tmd->res);
351: if (BCR_SWSTYLE(s) == 3) {
352: uint32_t tmp = xda.tbadr;
353: xda.tbadr = xda.misc;
354: xda.misc = tmp;
1.1 root 355: }
1.1.1.3 root 356: s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
1.1 root 357: }
358: }
359:
1.1.1.3 root 360: static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
1.1.1.2 root 361: target_phys_addr_t addr)
1.1 root 362: {
1.1.1.3 root 363: if (!BCR_SSIZE32(s)) {
364: struct {
365: uint32_t rbadr;
366: int16_t buf_length;
367: int16_t msg_length;
368: } rda;
369: s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
370: rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
371: rmd->buf_length = le16_to_cpu(rda.buf_length);
372: rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
373: rmd->msg_length = le16_to_cpu(rda.msg_length);
374: rmd->res = 0;
1.1.1.2 root 375: } else {
1.1.1.3 root 376: s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
377: le32_to_cpus(&rmd->rbadr);
378: le16_to_cpus((uint16_t *)&rmd->buf_length);
379: le16_to_cpus((uint16_t *)&rmd->status);
380: le32_to_cpus(&rmd->msg_length);
381: le32_to_cpus(&rmd->res);
382: if (BCR_SWSTYLE(s) == 3) {
383: uint32_t tmp = rmd->rbadr;
384: rmd->rbadr = rmd->msg_length;
385: rmd->msg_length = tmp;
1.1.1.2 root 386: }
1.1 root 387: }
388: }
389:
1.1.1.3 root 390: static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
1.1.1.2 root 391: target_phys_addr_t addr)
1.1 root 392: {
1.1.1.3 root 393: if (!BCR_SSIZE32(s)) {
394: struct {
395: uint32_t rbadr;
396: int16_t buf_length;
397: int16_t msg_length;
398: } rda;
399: rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
400: ((rmd->status & 0xff00) << 16));
401: rda.buf_length = cpu_to_le16(rmd->buf_length);
402: rda.msg_length = cpu_to_le16(rmd->msg_length);
403: s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
1.1.1.2 root 404: } else {
1.1.1.3 root 405: struct {
406: uint32_t rbadr;
407: int16_t buf_length;
408: int16_t status;
409: uint32_t msg_length;
410: uint32_t res;
411: } rda;
412: rda.rbadr = cpu_to_le32(rmd->rbadr);
413: rda.buf_length = cpu_to_le16(rmd->buf_length);
414: rda.status = cpu_to_le16(rmd->status);
415: rda.msg_length = cpu_to_le32(rmd->msg_length);
416: rda.res = cpu_to_le32(rmd->res);
417: if (BCR_SWSTYLE(s) == 3) {
418: uint32_t tmp = rda.rbadr;
419: rda.rbadr = rda.msg_length;
420: rda.msg_length = tmp;
1.1 root 421: }
1.1.1.3 root 422: s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
1.1 root 423: }
424: }
425:
426:
427: #define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
428:
429: #define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
430:
431: #define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
432:
433: #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
434:
435: #if 1
436:
437: #define CHECK_RMD(ADDR,RES) do { \
438: struct pcnet_RMD rmd; \
439: RMDLOAD(&rmd,(ADDR)); \
1.1.1.3 root 440: (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
441: || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
1.1 root 442: } while (0)
443:
444: #define CHECK_TMD(ADDR,RES) do { \
445: struct pcnet_TMD tmd; \
446: TMDLOAD(&tmd,(ADDR)); \
1.1.1.3 root 447: (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
1.1 root 448: } while (0)
449:
450: #else
451:
452: #define CHECK_RMD(ADDR,RES) do { \
453: switch (BCR_SWSTYLE(s)) { \
454: case 0x00: \
455: do { \
456: uint16_t rda[4]; \
1.1.1.3 root 457: s->phys_mem_read(s->dma_opaque, (ADDR), \
458: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 459: (RES) |= (rda[2] & 0xf000)!=0xf000; \
460: (RES) |= (rda[3] & 0xf000)!=0x0000; \
461: } while (0); \
462: break; \
463: case 0x01: \
464: case 0x02: \
465: do { \
466: uint32_t rda[4]; \
1.1.1.3 root 467: s->phys_mem_read(s->dma_opaque, (ADDR), \
1.1.1.2 root 468: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 469: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
470: (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
471: } while (0); \
472: break; \
473: case 0x03: \
474: do { \
475: uint32_t rda[4]; \
1.1.1.3 root 476: s->phys_mem_read(s->dma_opaque, (ADDR), \
1.1.1.2 root 477: (void *)&rda[0], sizeof(rda), 0); \
1.1 root 478: (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
479: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
480: } while (0); \
481: break; \
482: } \
483: } while (0)
484:
485: #define CHECK_TMD(ADDR,RES) do { \
486: switch (BCR_SWSTYLE(s)) { \
487: case 0x00: \
488: do { \
489: uint16_t xda[4]; \
1.1.1.3 root 490: s->phys_mem_read(s->dma_opaque, (ADDR), \
491: (void *)&xda[0], sizeof(xda), 0); \
492: (RES) |= (xda[2] & 0xf000)!=0xf000; \
1.1 root 493: } while (0); \
494: break; \
495: case 0x01: \
496: case 0x02: \
497: case 0x03: \
498: do { \
499: uint32_t xda[4]; \
1.1.1.3 root 500: s->phys_mem_read(s->dma_opaque, (ADDR), \
501: (void *)&xda[0], sizeof(xda), 0); \
1.1 root 502: (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
503: } while (0); \
504: break; \
505: } \
506: } while (0)
507:
508: #endif
509:
510: #define PRINT_PKTHDR(BUF) do { \
1.1.1.3 root 511: struct qemu_ether_header *hdr = (void *)(BUF); \
512: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
513: "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
514: "type=0x%04x\n", \
1.1 root 515: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
516: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
517: hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
518: hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
1.1.1.3 root 519: be16_to_cpu(hdr->ether_type)); \
1.1 root 520: } while (0)
521:
522: #define MULTICAST_FILTER_LEN 8
523:
524: static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
525: {
526: #define LNC_POLYNOMIAL 0xEDB88320UL
527: uint32_t crc = 0xFFFFFFFF;
528: int idx, bit;
529: uint8_t data;
530:
531: for (idx = 0; idx < 6; idx++) {
532: for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
533: crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
534: data >>= 1;
535: }
536: }
537: return crc;
538: #undef LNC_POLYNOMIAL
539: }
540:
541: #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
542:
543: /* generated using the AUTODIN II polynomial
544: * x^32 + x^26 + x^23 + x^22 + x^16 +
545: * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
546: */
547: static const uint32_t crctab[256] = {
548: 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
549: 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
550: 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
551: 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
552: 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
553: 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
554: 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
555: 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
556: 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
557: 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
558: 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
559: 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
560: 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
561: 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
562: 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
563: 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
564: 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
565: 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
566: 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
567: 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
568: 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
569: 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
570: 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
571: 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
572: 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
573: 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
574: 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
575: 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
576: 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
577: 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
578: 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
579: 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
580: 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
581: 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
582: 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
583: 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
584: 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
585: 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
586: 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
587: 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
588: 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
589: 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
590: 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
591: 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
592: 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
593: 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
594: 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
595: 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
596: 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
597: 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
598: 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
599: 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
600: 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
601: 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
602: 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
603: 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
604: 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
605: 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
606: 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
607: 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
608: 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
609: 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
610: 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
611: 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
612: };
613:
614: static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
615: {
616: struct qemu_ether_header *hdr = (void *)buf;
1.1.1.3 root 617: uint8_t padr[6] = {
1.1 root 618: s->csr[12] & 0xff, s->csr[12] >> 8,
619: s->csr[13] & 0xff, s->csr[13] >> 8,
1.1.1.3 root 620: s->csr[14] & 0xff, s->csr[14] >> 8
1.1 root 621: };
622: int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
623: #ifdef PCNET_DEBUG_MATCH
624: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
625: "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
626: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
627: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
628: padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
629: printf("padr_match result=%d\n", result);
630: #endif
631: return result;
632: }
633:
634: static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
635: {
1.1.1.2 root 636: static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1.1 root 637: struct qemu_ether_header *hdr = (void *)buf;
638: int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
639: #ifdef PCNET_DEBUG_MATCH
640: printf("padr_bcast result=%d\n", result);
641: #endif
642: return result;
643: }
644:
645: static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
646: {
647: struct qemu_ether_header *hdr = (void *)buf;
1.1.1.3 root 648: if ((*(hdr->ether_dhost)&0x01) &&
1.1 root 649: ((uint64_t *)&s->csr[8])[0] != 0LL) {
1.1.1.3 root 650: uint8_t ladr[8] = {
1.1 root 651: s->csr[8] & 0xff, s->csr[8] >> 8,
652: s->csr[9] & 0xff, s->csr[9] >> 8,
1.1.1.3 root 653: s->csr[10] & 0xff, s->csr[10] >> 8,
654: s->csr[11] & 0xff, s->csr[11] >> 8
1.1 root 655: };
656: int index = lnc_mchash(hdr->ether_dhost) >> 26;
657: return !!(ladr[index >> 3] & (1 << (index & 7)));
658: }
659: return 0;
660: }
661:
1.1.1.3 root 662: static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
1.1 root 663: {
664: while (idx < 1) idx += CSR_RCVRL(s);
665: return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
666: }
667:
668: static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
669: {
1.1.1.3 root 670: int64_t next_time = current_time +
671: muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
1.1.1.8 root 672: get_ticks_per_sec(), 33000000L);
1.1 root 673: if (next_time <= current_time)
674: next_time = current_time + 1;
675: return next_time;
676: }
677:
678: static void pcnet_poll(PCNetState *s);
679: static void pcnet_poll_timer(void *opaque);
680:
681: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
682: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
683: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
684:
685: static void pcnet_s_reset(PCNetState *s)
686: {
687: #ifdef PCNET_DEBUG
688: printf("pcnet_s_reset\n");
689: #endif
690:
691: s->lnkst = 0x40;
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
888: s->csr[0] &= ~0x7feb;
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.4 root 1238: if (!GET_FIELD(tmd.status, TMDS, ENP)) {
1239: int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
1240: s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
1241: s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
1242: s->xmit_pos += bcnt;
1243: } else if (s->xmit_pos >= 0) {
1.1.1.3 root 1244: int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
1245: s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
1246: s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
1247: s->xmit_pos += bcnt;
1.1 root 1248: #ifdef PCNET_DEBUG
1249: printf("pcnet_transmit size=%d\n", s->xmit_pos);
1.1.1.3 root 1250: #endif
1.1.1.4 root 1251: if (CSR_LOOP(s)) {
1252: if (BCR_SWSTYLE(s) == 1)
1253: add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
1254: s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
1.1.1.8 root 1255: pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos);
1.1.1.4 root 1256: s->looptest = 0;
1257: } else
1.1.1.8 root 1258: if (s->nic)
1259: qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos);
1.1 root 1260:
1261: s->csr[0] &= ~0x0008; /* clear TDMD */
1262: s->csr[4] |= 0x0004; /* set TXSTRT */
1263: s->xmit_pos = -1;
1264: }
1265:
1.1.1.3 root 1266: SET_FIELD(&tmd.status, TMDS, OWN, 0);
1.1 root 1267: TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1.1.1.3 root 1268: if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
1.1 root 1269: s->csr[0] |= 0x0200; /* set TINT */
1270:
1271: if (CSR_XMTRC(s)<=1)
1272: CSR_XMTRC(s) = CSR_XMTRL(s);
1273: else
1274: CSR_XMTRC(s)--;
1275: if (count--)
1276: goto txagain;
1277:
1.1.1.3 root 1278: } else
1.1 root 1279: if (s->xmit_pos >= 0) {
1280: struct pcnet_TMD tmd;
1.1.1.6 root 1281: TMDLOAD(&tmd, xmit_cxda);
1.1.1.3 root 1282: SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
1283: SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
1284: SET_FIELD(&tmd.status, TMDS, ERR, 1);
1285: SET_FIELD(&tmd.status, TMDS, OWN, 0);
1.1.1.6 root 1286: TMDSTORE(&tmd, xmit_cxda);
1.1 root 1287: s->csr[0] |= 0x0200; /* set TINT */
1288: if (!CSR_DXSUFLO(s)) {
1289: s->csr[0] &= ~0x0010;
1290: } else
1291: if (count--)
1292: goto txagain;
1293: }
1294:
1295: s->tx_busy = 0;
1296: }
1297:
1298: static void pcnet_poll(PCNetState *s)
1299: {
1300: if (CSR_RXON(s)) {
1301: pcnet_rdte_poll(s);
1302: }
1303:
1.1.1.3 root 1304: if (CSR_TDMD(s) ||
1.1 root 1305: (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
1306: {
1307: /* prevent recursion */
1308: if (s->tx_busy)
1309: return;
1310:
1311: pcnet_transmit(s);
1312: }
1313: }
1314:
1315: static void pcnet_poll_timer(void *opaque)
1316: {
1317: PCNetState *s = opaque;
1318:
1319: qemu_del_timer(s->poll_timer);
1320:
1321: if (CSR_TDMD(s)) {
1322: pcnet_transmit(s);
1323: }
1324:
1.1.1.3 root 1325: pcnet_update_irq(s);
1.1 root 1326:
1327: if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
1.1.1.11 root 1328: uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
1.1 root 1329: if (!s->timer || !now)
1330: s->timer = now;
1331: else {
1332: uint64_t t = now - s->timer + CSR_POLL(s);
1333: if (t > 0xffffLL) {
1334: pcnet_poll(s);
1335: CSR_POLL(s) = CSR_PINT(s);
1336: } else
1337: CSR_POLL(s) = t;
1338: }
1.1.1.3 root 1339: qemu_mod_timer(s->poll_timer,
1.1.1.11 root 1340: pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
1.1 root 1341: }
1342: }
1343:
1344:
1345: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
1346: {
1347: uint16_t val = new_value;
1348: #ifdef PCNET_DEBUG_CSR
1349: printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
1350: #endif
1351: switch (rap) {
1352: case 0:
1353: s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
1354:
1355: s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
1356:
1357: val = (val & 0x007f) | (s->csr[0] & 0x7f00);
1358:
1359: /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
1360: if ((val&7) == 7)
1361: val &= ~3;
1362:
1363: if (!CSR_STOP(s) && (val & 4))
1364: pcnet_stop(s);
1365:
1366: if (!CSR_INIT(s) && (val & 1))
1367: pcnet_init(s);
1368:
1369: if (!CSR_STRT(s) && (val & 2))
1370: pcnet_start(s);
1371:
1.1.1.3 root 1372: if (CSR_TDMD(s))
1.1 root 1373: pcnet_transmit(s);
1374:
1375: return;
1376: case 1:
1377: case 2:
1378: case 8:
1379: case 9:
1380: case 10:
1381: case 11:
1382: case 12:
1383: case 13:
1384: case 14:
1385: case 15:
1386: case 18: /* CRBAL */
1387: case 19: /* CRBAU */
1388: case 20: /* CXBAL */
1389: case 21: /* CXBAU */
1390: case 22: /* NRBAU */
1391: case 23: /* NRBAU */
1392: case 24:
1393: case 25:
1394: case 26:
1395: case 27:
1396: case 28:
1397: case 29:
1398: case 30:
1399: case 31:
1400: case 32:
1401: case 33:
1402: case 34:
1403: case 35:
1404: case 36:
1405: case 37:
1406: case 38:
1407: case 39:
1408: case 40: /* CRBC */
1409: case 41:
1410: case 42: /* CXBC */
1411: case 43:
1412: case 44:
1413: case 45:
1414: case 46: /* POLL */
1415: case 47: /* POLLINT */
1416: case 72:
1417: case 74:
1418: case 76: /* RCVRL */
1419: case 78: /* XMTRL */
1420: case 112:
1421: if (CSR_STOP(s) || CSR_SPND(s))
1422: break;
1423: return;
1424: case 3:
1425: break;
1426: case 4:
1.1.1.3 root 1427: s->csr[4] &= ~(val & 0x026a);
1.1 root 1428: val &= ~0x026a; val |= s->csr[4] & 0x026a;
1429: break;
1430: case 5:
1.1.1.3 root 1431: s->csr[5] &= ~(val & 0x0a90);
1.1 root 1432: val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
1433: break;
1434: case 16:
1435: pcnet_csr_writew(s,1,val);
1436: return;
1437: case 17:
1438: pcnet_csr_writew(s,2,val);
1439: return;
1440: case 58:
1441: pcnet_bcr_writew(s,BCR_SWS,val);
1442: break;
1443: default:
1444: return;
1445: }
1446: s->csr[rap] = val;
1447: }
1448:
1449: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
1450: {
1451: uint32_t val;
1452: switch (rap) {
1453: case 0:
1454: pcnet_update_irq(s);
1455: val = s->csr[0];
1456: val |= (val & 0x7800) ? 0x8000 : 0;
1457: break;
1458: case 16:
1459: return pcnet_csr_readw(s,1);
1460: case 17:
1461: return pcnet_csr_readw(s,2);
1462: case 58:
1463: return pcnet_bcr_readw(s,BCR_SWS);
1464: case 88:
1465: val = s->csr[89];
1466: val <<= 16;
1467: val |= s->csr[88];
1468: break;
1469: default:
1470: val = s->csr[rap];
1471: }
1472: #ifdef PCNET_DEBUG_CSR
1473: printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
1474: #endif
1475: return val;
1476: }
1477:
1478: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
1479: {
1480: rap &= 127;
1481: #ifdef PCNET_DEBUG_BCR
1482: printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
1483: #endif
1484: switch (rap) {
1485: case BCR_SWS:
1486: if (!(CSR_STOP(s) || CSR_SPND(s)))
1487: return;
1488: val &= ~0x0300;
1489: switch (val & 0x00ff) {
1490: case 0:
1491: val |= 0x0200;
1492: break;
1493: case 1:
1494: val |= 0x0100;
1495: break;
1496: case 2:
1497: case 3:
1498: val |= 0x0300;
1499: break;
1500: default:
1501: printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
1502: val = 0x0200;
1503: break;
1504: }
1505: #ifdef PCNET_DEBUG
1506: printf("BCR_SWS=0x%04x\n", val);
1507: #endif
1508: case BCR_LNKST:
1509: case BCR_LED1:
1510: case BCR_LED2:
1511: case BCR_LED3:
1512: case BCR_MC:
1513: case BCR_FDC:
1514: case BCR_BSBC:
1515: case BCR_EECAS:
1516: case BCR_PLAT:
1517: s->bcr[rap] = val;
1518: break;
1519: default:
1520: break;
1521: }
1522: }
1523:
1.1.1.10 root 1524: uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
1.1 root 1525: {
1526: uint32_t val;
1527: rap &= 127;
1528: switch (rap) {
1529: case BCR_LNKST:
1530: case BCR_LED1:
1531: case BCR_LED2:
1532: case BCR_LED3:
1533: val = s->bcr[rap] & ~0x8000;
1534: val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
1535: break;
1536: default:
1537: val = rap < 32 ? s->bcr[rap] : 0;
1538: break;
1539: }
1540: #ifdef PCNET_DEBUG_BCR
1541: printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
1542: #endif
1543: return val;
1544: }
1545:
1.1.1.8 root 1546: void pcnet_h_reset(void *opaque)
1.1 root 1547: {
1.1.1.2 root 1548: PCNetState *s = opaque;
1.1 root 1549:
1550: s->bcr[BCR_MSRDA] = 0x0005;
1551: s->bcr[BCR_MSWRA] = 0x0005;
1552: s->bcr[BCR_MC ] = 0x0002;
1553: s->bcr[BCR_LNKST] = 0x00c0;
1554: s->bcr[BCR_LED1 ] = 0x0084;
1555: s->bcr[BCR_LED2 ] = 0x0088;
1556: s->bcr[BCR_LED3 ] = 0x0090;
1557: s->bcr[BCR_FDC ] = 0x0000;
1558: s->bcr[BCR_BSBC ] = 0x9001;
1559: s->bcr[BCR_EECAS] = 0x0002;
1560: s->bcr[BCR_SWS ] = 0x0200;
1561: s->bcr[BCR_PLAT ] = 0xff06;
1562:
1563: pcnet_s_reset(s);
1.1.1.8 root 1564: pcnet_update_irq(s);
1565: pcnet_poll_timer(s);
1.1 root 1566: }
1567:
1.1.1.8 root 1568: void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
1.1 root 1569: {
1570: PCNetState *s = opaque;
1571: pcnet_poll_timer(s);
1572: #ifdef PCNET_DEBUG_IO
1573: printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
1574: #endif
1575: if (!BCR_DWIO(s)) {
1576: switch (addr & 0x0f) {
1577: case 0x00: /* RDP */
1578: pcnet_csr_writew(s, s->rap, val);
1579: break;
1580: case 0x02:
1581: s->rap = val & 0x7f;
1582: break;
1583: case 0x06:
1584: pcnet_bcr_writew(s, s->rap, val);
1585: break;
1586: }
1587: }
1588: pcnet_update_irq(s);
1589: }
1590:
1.1.1.8 root 1591: uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
1.1 root 1592: {
1593: PCNetState *s = opaque;
1594: uint32_t val = -1;
1595: pcnet_poll_timer(s);
1596: if (!BCR_DWIO(s)) {
1597: switch (addr & 0x0f) {
1598: case 0x00: /* RDP */
1599: val = pcnet_csr_readw(s, s->rap);
1600: break;
1601: case 0x02:
1602: val = s->rap;
1603: break;
1604: case 0x04:
1605: pcnet_s_reset(s);
1606: val = 0;
1607: break;
1608: case 0x06:
1609: val = pcnet_bcr_readw(s, s->rap);
1610: break;
1611: }
1612: }
1613: pcnet_update_irq(s);
1614: #ifdef PCNET_DEBUG_IO
1615: printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
1616: #endif
1617: return val;
1618: }
1619:
1.1.1.10 root 1620: void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
1.1 root 1621: {
1622: PCNetState *s = opaque;
1623: pcnet_poll_timer(s);
1624: #ifdef PCNET_DEBUG_IO
1625: printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
1626: #endif
1627: if (BCR_DWIO(s)) {
1628: switch (addr & 0x0f) {
1629: case 0x00: /* RDP */
1630: pcnet_csr_writew(s, s->rap, val & 0xffff);
1631: break;
1632: case 0x04:
1633: s->rap = val & 0x7f;
1634: break;
1635: case 0x0c:
1636: pcnet_bcr_writew(s, s->rap, val & 0xffff);
1637: break;
1638: }
1639: } else
1640: if ((addr & 0x0f) == 0) {
1641: /* switch device to dword i/o mode */
1642: pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
1643: #ifdef PCNET_DEBUG_IO
1644: printf("device switched into dword i/o mode\n");
1.1.1.3 root 1645: #endif
1.1 root 1646: }
1647: pcnet_update_irq(s);
1648: }
1649:
1.1.1.10 root 1650: uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
1.1 root 1651: {
1652: PCNetState *s = opaque;
1653: uint32_t val = -1;
1654: pcnet_poll_timer(s);
1.1.1.3 root 1655: if (BCR_DWIO(s)) {
1.1 root 1656: switch (addr & 0x0f) {
1657: case 0x00: /* RDP */
1658: val = pcnet_csr_readw(s, s->rap);
1659: break;
1660: case 0x04:
1661: val = s->rap;
1662: break;
1663: case 0x08:
1664: pcnet_s_reset(s);
1665: val = 0;
1666: break;
1667: case 0x0c:
1668: val = pcnet_bcr_readw(s, s->rap);
1669: break;
1670: }
1671: }
1672: pcnet_update_irq(s);
1673: #ifdef PCNET_DEBUG_IO
1674: printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
1675: #endif
1676: return val;
1677: }
1678:
1.1.1.8 root 1679: static bool is_version_2(void *opaque, int version_id)
1.1.1.2 root 1680: {
1.1.1.8 root 1681: return version_id == 2;
1.1.1.2 root 1682: }
1683:
1.1.1.8 root 1684: const VMStateDescription vmstate_pcnet = {
1685: .name = "pcnet",
1686: .version_id = 3,
1687: .minimum_version_id = 2,
1688: .minimum_version_id_old = 2,
1689: .fields = (VMStateField []) {
1690: VMSTATE_INT32(rap, PCNetState),
1691: VMSTATE_INT32(isr, PCNetState),
1692: VMSTATE_INT32(lnkst, PCNetState),
1693: VMSTATE_UINT32(rdra, PCNetState),
1694: VMSTATE_UINT32(tdra, PCNetState),
1695: VMSTATE_BUFFER(prom, PCNetState),
1696: VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
1697: VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
1698: VMSTATE_UINT64(timer, PCNetState),
1699: VMSTATE_INT32(xmit_pos, PCNetState),
1700: VMSTATE_BUFFER(buffer, PCNetState),
1701: VMSTATE_UNUSED_TEST(is_version_2, 4),
1702: VMSTATE_INT32(tx_busy, PCNetState),
1703: VMSTATE_TIMER(poll_timer, PCNetState),
1704: VMSTATE_END_OF_LIST()
1705: }
1706: };
1.1.1.2 root 1707:
1.1.1.8 root 1708: void pcnet_common_cleanup(PCNetState *d)
1.1.1.5 root 1709: {
1.1.1.8 root 1710: d->nic = NULL;
1.1.1.5 root 1711: }
1712:
1.1.1.8 root 1713: int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
1.1.1.2 root 1714: {
1.1.1.11 root 1715: int i;
1716: uint16_t checksum;
1717:
1718: s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
1.1.1.2 root 1719:
1.1.1.8 root 1720: qemu_macaddr_default_if_unset(&s->conf.macaddr);
1721: s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
1722: qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
1.1.1.5 root 1723:
1.1.1.10 root 1724: add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
1.1.1.5 root 1725:
1.1.1.11 root 1726: /* Initialize the PROM */
1727:
1728: /*
1729: Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
1730: page 95
1731: */
1732: memcpy(s->prom, s->conf.macaddr.a, 6);
1733: /* Reserved Location: must be 00h */
1734: s->prom[6] = s->prom[7] = 0x00;
1735: /* Reserved Location: must be 00h */
1736: s->prom[8] = 0x00;
1737: /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
1738: s->prom[9] = 0x11;
1739: /* User programmable space, init with 0 */
1740: s->prom[10] = s->prom[11] = 0x00;
1741: /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
1742: and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
1743: s->prom[12] = s->prom[13] = 0x00;
1744: /* Must be ASCII W (57h) if compatibility to AMD
1745: driver software is desired */
1746: s->prom[14] = s->prom[15] = 0x57;
1747:
1748: for (i = 0, checksum = 0; i < 16; i++) {
1749: checksum += s->prom[i];
1750: }
1751: *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
1752:
1.1.1.5 root 1753: return 0;
1754: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.